diff --git a/pom.xml b/pom.xml index f5e23c19..892468fe 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ - 3.4.1 + 3.6.0-SNAPSHOT 3.3.0 3.0.1.Final @@ -206,5 +206,6 @@ zanata-client-commands zanata-maven-plugin zanata-rest-client + rest-client - + \ No newline at end of file diff --git a/rest-client/pom.xml b/rest-client/pom.xml new file mode 100644 index 00000000..7e845ab0 --- /dev/null +++ b/rest-client/pom.xml @@ -0,0 +1,102 @@ + + + 4.0.0 + + org.zanata + client + 3.6.0-SNAPSHOT + + rest-client + rest-client + http://maven.apache.org + + UTF-8 + + + + org.zanata + zanata-common-api + + + org.jboss.resteasy + resteasy-jaxrs + + + org.jboss.resteasy + resteasy-jaxb-provider + + + org.jboss.resteasy + jaxrs-api + + + org.jboss.resteasy + resteasy-multipart-provider + + + + + com.sun.jersey + jersey-core + 1.17.1 + + + com.sun.jersey + jersey-client + 1.17.1 + + + com.sun.jersey.contribs + jersey-multipart + 1.17.1 + + + + org.slf4j + slf4j-api + + + log4j + log4j + + + org.slf4j + slf4j-log4j12 + + + + com.google.guava + guava + + + commons-codec + commons-codec + + + + + junit + junit + test + + + org.hamcrest + hamcrest-core + test + + + org.hamcrest + hamcrest-library + test + + + + + + + src/test/resources + + + + diff --git a/rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderFilter.java b/rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderFilter.java new file mode 100644 index 00000000..9be0d28e --- /dev/null +++ b/rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderFilter.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.rest.client; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.Provider; + +import org.zanata.rest.RestConstant; + +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.ClientRequest; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.filter.ClientFilter; + +@Provider +public class ApiKeyHeaderFilter extends ClientFilter { + private String apiKey; + private String username; + private String ver; + + public ApiKeyHeaderFilter(String username, String apiKey, String ver) { + this.username = username; + this.apiKey = apiKey; + this.ver = ver; + } + + @Override + public ClientResponse handle(ClientRequest cr) + throws ClientHandlerException { + MultivaluedMap headers = cr.getHeaders(); + headers.add(RestConstant.HEADER_USERNAME, username); + headers.add(RestConstant.HEADER_API_KEY, apiKey); + headers.add(RestConstant.HEADER_VERSION_NO, ver); + return getNext().handle(cr); + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/rest-client/src/main/java/org/zanata/rest/client/CacheResponseFilter.java b/rest-client/src/main/java/org/zanata/rest/client/CacheResponseFilter.java new file mode 100644 index 00000000..bee5a842 --- /dev/null +++ b/rest-client/src/main/java/org/zanata/rest/client/CacheResponseFilter.java @@ -0,0 +1,65 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.rest.client; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.ClientRequest; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.GenericType; +import com.sun.jersey.api.client.filter.ClientFilter; + +/** + * This is a workaround that jersey client don't support put/post returning + * response. + * + * @author Patrick Huang pahuang@redhat.com + */ +public class CacheResponseFilter extends ClientFilter { + private Optional cachedClientResponse = Optional.absent(); + + @Override + public ClientResponse handle(ClientRequest cr) + throws ClientHandlerException { + ClientResponse response = getNext().handle(cr); + response.bufferEntity(); + cachedClientResponse = Optional.of(response); + return response; + } + + public T getEntity(Class type) { + checkState(); + return cachedClientResponse.get().getEntity(type); + } + + public T getEntity(GenericType genericType) { + checkState(); + return cachedClientResponse.get().getEntity(genericType); + } + + private void checkState() { + Preconditions.checkState(cachedClientResponse.isPresent(), + "No cached ClientResponse. Did you forget to add this filter?"); + } +} diff --git a/rest-client/src/main/java/org/zanata/rest/client/FileResourceClient.java b/rest-client/src/main/java/org/zanata/rest/client/FileResourceClient.java new file mode 100644 index 00000000..380d49ba --- /dev/null +++ b/rest-client/src/main/java/org/zanata/rest/client/FileResourceClient.java @@ -0,0 +1,132 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.rest.client; + +import java.net.URI; +import javax.ws.rs.core.MediaType; + +import org.zanata.rest.DocumentFileUploadForm; +import org.zanata.rest.StringSet; +import org.zanata.rest.dto.ChunkUploadResponse; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.multipart.FormDataMultiPart; + +/** + * @author Patrick Huang pahuang@redhat.com + */ +public class FileResourceClient { + private final RestClientFactory factory; + + private final URI baseUri; + + public FileResourceClient(RestClientFactory restClientFactory) { + this.factory = restClientFactory; + baseUri = restClientFactory.getBaseUri(); + + } + + public StringSet acceptedFileTypes() { + String types = factory.getClient() + .resource(baseUri) + .path("file").path("accepted_types") + .get(String.class); + return new StringSet(types); + } + + public ChunkUploadResponse uploadSourceFile( + String projectSlug, + String iterationSlug, String docId, + DocumentFileUploadForm documentFileUploadForm) { + CacheResponseFilter filter = new CacheResponseFilter(); + Client client = factory.getClient(); + client.addFilter(filter); + WebResource.Builder builder = client + .resource(baseUri) + .path("file").path("source").path(projectSlug) + .path(iterationSlug) + .queryParam("docId", docId) + .type(MediaType.MULTIPART_FORM_DATA_TYPE); + FormDataMultiPart form = + prepareFormDataMultiPart(documentFileUploadForm); + + builder.post(form); + ChunkUploadResponse chunkUploadResponse = + filter.getEntity(ChunkUploadResponse.class); + client.removeFilter(filter); + return chunkUploadResponse; + } + + private FormDataMultiPart prepareFormDataMultiPart( + DocumentFileUploadForm documentFileUploadForm) { + FormDataMultiPart form = + new FormDataMultiPart() + .field("file", documentFileUploadForm + .getFileStream(), + MediaType.APPLICATION_OCTET_STREAM_TYPE); + addBodyPartIfPresent(form, "adapterParams", + documentFileUploadForm.getAdapterParams()); + addBodyPartIfPresent(form, "type", documentFileUploadForm.getFileType()); + addBodyPartIfPresent(form, "first", documentFileUploadForm.getFirst()); + addBodyPartIfPresent(form, "hash", documentFileUploadForm.getHash()); + addBodyPartIfPresent(form, "last", documentFileUploadForm.getLast()); + addBodyPartIfPresent(form, "size", documentFileUploadForm.getSize()); + addBodyPartIfPresent(form, "uploadId", + documentFileUploadForm.getUploadId()); + return form; + } + + public ChunkUploadResponse uploadTranslationFile( + String projectSlug, + String iterationSlug, String locale, String docId, + String mergeType, + DocumentFileUploadForm documentFileUploadForm) { + CacheResponseFilter filter = new CacheResponseFilter(); + Client client = factory.getClient(); + client.addFilter(filter); + WebResource.Builder builder = client.resource(baseUri) + .path("file").path("translation") + .path(projectSlug) + .path(iterationSlug) + .path(locale) + .queryParam("docId", docId) + .queryParam("merge", mergeType) + .type(MediaType.MULTIPART_FORM_DATA_TYPE); + FormDataMultiPart form = + prepareFormDataMultiPart(documentFileUploadForm); + + builder.post(form); + ChunkUploadResponse chunkUploadResponse = + filter.getEntity(ChunkUploadResponse.class); + client.removeFilter(filter); + return chunkUploadResponse; + } + + private static FormDataMultiPart addBodyPartIfPresent( + FormDataMultiPart form, String field, T value) { + if (value != null) { + return form.field(field, value.toString()); + } + return form; + } +} diff --git a/rest-client/src/main/java/org/zanata/rest/client/RestClientFactory.java b/rest-client/src/main/java/org/zanata/rest/client/RestClientFactory.java new file mode 100644 index 00000000..35540a83 --- /dev/null +++ b/rest-client/src/main/java/org/zanata/rest/client/RestClientFactory.java @@ -0,0 +1,175 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.rest.client; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zanata.rest.dto.VersionInfo; +import com.google.common.base.Throwables; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.config.ClientConfig; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import com.sun.jersey.client.urlconnection.HTTPSProperties; +import com.sun.jersey.multipart.impl.MultiPartWriter; + +/** + * @author Patrick Huang pahuang@redhat.com + */ +public class RestClientFactory { + private static final Logger log = + LoggerFactory.getLogger(RestClientFactory.class); + private String clientVersion; + private VersionInfo clientApiVersion; + + private Client client; + private URI baseURI; + + public RestClientFactory(URI base, String username, String apiKey, + VersionInfo clientApiVersion, boolean logHttp, + boolean sslCertDisabled) { + baseURI = base; + this.clientApiVersion = clientApiVersion; + clientVersion = clientApiVersion.getVersionNo(); + DefaultClientConfig clientConfig = + new DefaultClientConfig(MultiPartWriter.class); + + sslConfiguration(sslCertDisabled, clientConfig); + + client = Client.create(clientConfig); + client.addFilter( + new ApiKeyHeaderFilter(username, apiKey, clientVersion)); + client.addFilter(new TraceDebugInterceptor(logHttp)); + } + + private static void sslConfiguration(boolean sslCertDisabled, + ClientConfig clientConfig) { + if (!sslCertDisabled) { + return; + } + try { + final SSLContext sslContext = SSLContext.getInstance("TLS"); + + // Create a trust manager that does not validate certificate chains + // against our server + final TrustManager[] trustAllCerts; + trustAllCerts = + new TrustManager[] { new AcceptAllX509TrustManager() }; + sslContext.init(null, trustAllCerts, new SecureRandom()); + HttpsURLConnection + .setDefaultSSLSocketFactory(sslContext + .getSocketFactory()); + clientConfig.getProperties().put( + HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, + new HTTPSProperties( + new HostnameVerifier() { + @Override + public boolean verify(String s, + SSLSession sslSession) { + // whatever your matching policy states + return true; + } + }, sslContext + )); + } catch (Exception e) { + log.warn("error creating SSL client", e); + Throwables.propagate(e); + } + } + + public VersionInfo getServerVersionInfo() { + return client.resource(getBaseUri()).path("version") + .get(VersionInfo.class); + } + + private URL getBaseUrl() { + try { + return new URL(fixBase(baseURI).toString() + getUrlPrefix()); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + protected URI getBaseUri() { + try { + return getBaseUrl().toURI(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + private static URI fixBase(URI base) { + if (base != null) { + String baseString = base.toString(); + if (!baseString.endsWith("/")) { + try { + URI result = new URI(baseString + "/"); + log.warn("Appending '/' to base URL '{}': using '{}'", + baseString, result); + return result; + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + } + return base; + } + + protected String getUrlPrefix() { + return "rest/"; + } + + protected Client getClient() { + return client; + } + + private static class AcceptAllX509TrustManager implements X509TrustManager { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void + checkClientTrusted(X509Certificate[] certs, String authType) + throws CertificateException { + } + + public void + checkServerTrusted(X509Certificate[] certs, String authType) + throws CertificateException { + } + } +} diff --git a/rest-client/src/main/java/org/zanata/rest/client/SourceDocResourceClient.java b/rest-client/src/main/java/org/zanata/rest/client/SourceDocResourceClient.java new file mode 100644 index 00000000..b6dfb552 --- /dev/null +++ b/rest-client/src/main/java/org/zanata/rest/client/SourceDocResourceClient.java @@ -0,0 +1,63 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.rest.client; + +import java.net.URI; +import java.util.List; +import java.util.Set; + +import org.zanata.rest.dto.resource.ResourceMeta; +import com.sun.jersey.api.client.GenericType; +import com.sun.jersey.api.client.WebResource; + +/** + * @author Patrick Huang + * pahuang@redhat.com + */ +public class SourceDocResourceClient { + private final RestClientFactory factory; + private final String project; + private final String projectVersion; + private final URI baseUri; + + public SourceDocResourceClient(RestClientFactory factory, String project, String projectVersion) { + this.factory = factory; + this.project = project; + this.projectVersion = projectVersion; + baseUri = factory.getBaseUri(); + } + + public List getResourceMeta(Set extensions) { + WebResource webResource = + factory.getClient().resource(baseUri) + .path("projects").path("p") + .path(project) + .path("iterations").path("i") + .path(projectVersion) + .path("r"); + if (extensions != null) { + webResource = webResource.queryParam("ext", extensions.toString()); + } + return webResource + .get(new GenericType>() {}); + } +} diff --git a/rest-client/src/main/java/org/zanata/rest/client/StatisticsResourceClient.java b/rest-client/src/main/java/org/zanata/rest/client/StatisticsResourceClient.java new file mode 100644 index 00000000..4a452a2e --- /dev/null +++ b/rest-client/src/main/java/org/zanata/rest/client/StatisticsResourceClient.java @@ -0,0 +1,78 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.rest.client; + +import java.net.URI; +import java.util.Arrays; +import javax.ws.rs.DefaultValue; + +import org.zanata.rest.dto.stats.ContainerTranslationStatistics; +import org.zanata.rest.dto.stats.contribution.ContributionStatistics; +import org.zanata.rest.service.StatisticsResource; +import com.sun.jersey.api.client.WebResource; + +/** + * @author Patrick Huang + * pahuang@redhat.com + */ +public class StatisticsResourceClient implements StatisticsResource { + private final RestClientFactory factory; + private final URI baseUri; + + public StatisticsResourceClient(RestClientFactory factory) { + this.factory = factory; + baseUri = factory.getBaseUri(); + } + + @Override + public ContainerTranslationStatistics getStatistics(String projectSlug, + String iterationSlug, @DefaultValue("false") boolean includeDetails, + @DefaultValue("false") boolean includeWordStats, String[] locales) { + WebResource webResource = + factory.getClient().resource(baseUri).path("stats") + .path("proj") + .path(projectSlug) + .path("iter") + .path(iterationSlug) + .queryParam("detail", String.valueOf(includeDetails)) + .queryParam("word", String.valueOf(includeWordStats)) + .queryParam("locale", Arrays.toString(locales)); + return webResource.get(ContainerTranslationStatistics.class); + } + + @Override + public ContainerTranslationStatistics getStatistics(String projectSlug, + String iterationSlug, String docId, + @DefaultValue("false") boolean includeWordStats, String[] locales) { + //TODO implement + throw new UnsupportedOperationException("Implement me!"); + //return null; + } + + @Override + public ContributionStatistics getContributionStatistics(String projectSlug, + String versionSlug, String username, String dateRange) { + //TODO implement + throw new UnsupportedOperationException("Implement me!"); + //return null; + } +} diff --git a/rest-client/src/main/java/org/zanata/rest/client/TraceDebugInterceptor.java b/rest-client/src/main/java/org/zanata/rest/client/TraceDebugInterceptor.java new file mode 100644 index 00000000..d1a2f2e5 --- /dev/null +++ b/rest-client/src/main/java/org/zanata/rest/client/TraceDebugInterceptor.java @@ -0,0 +1,143 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.zanata.rest.client; + +import java.io.ByteArrayInputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.ws.rs.ext.Provider; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zanata.rest.RestConstant; + +import com.google.common.base.Charsets; +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.ClientRequest; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.filter.ClientFilter; + +/** + * Performs logging of Requests on the client side. This interceptor + * logs at the level TRACE, unless the option logHttp is set, in which case it + * will log as INFO. + * + * @author Patrick Huang + * pahuang@redhat.com + * + */ +@Provider +public class TraceDebugInterceptor extends ClientFilter { + + private static final Logger log = LoggerFactory + .getLogger(TraceDebugInterceptor.class); + + private boolean logHttp; + + @Override + public ClientResponse handle(ClientRequest cr) + throws ClientHandlerException { + if (!logHttp && !log.isTraceEnabled()) { + return getNext().handle(cr); + } + log(">> REST Request: " + cr.getMethod() + " => " + + cr.getURI()); + + // Log before sending a request + for (String key : cr.getHeaders().keySet()) { + String headerVal = + cr.getHeaders().get(key).toString(); + if (key.equals(RestConstant.HEADER_API_KEY)) { + headerVal = + this.maskHeaderValues( + cr.getHeaders() + .get(key)); + } + + log(">> Header: " + key + " = " + headerVal); + } + log(">> body: " + cr.getEntity()); + + + + ClientResponse response = getNext().handle(cr); + + // log after a response has been received + log("<< REST Response: " + response.getStatus() + + ":" + response.getClientResponseStatus()); + for (String key : response.getHeaders().keySet()) { + log("<< Header: " + key + " = " + + response.getHeaders().get(key)); + } + response.bufferEntity(); + log(">> Body: " + getPayloadAsString(response)); + return response; + } + + // this is jersey implementation specific + private String getPayloadAsString(ClientResponse response) { + ByteArrayInputStream entityInputStream = null; + try { + entityInputStream = + (ByteArrayInputStream) response.getEntityInputStream(); + int available = entityInputStream.available(); + byte[] data = new byte[available]; + entityInputStream.read(data); + return new String(data, 0, available, Charsets.UTF_8); + } catch (Exception e) { + log.warn("can't read response payload"); + return "[error reading response]"; + } finally { + if (entityInputStream != null) { + entityInputStream.reset(); + } + } + + } + + public TraceDebugInterceptor(boolean logHttp) { + this.logHttp = logHttp; + } + + private void log(String msg) { + if (logHttp) { + log.info(msg); + } else { + log.trace(msg); + } + } + + /** + * Masks a list of header values so they are not displayed as clear text in + * the logs. + */ + private String maskHeaderValues(List headerValues) { + List maskedList = new ArrayList(headerValues.size()); + + for (Object actualValue : headerValues) { + // mask all characters with stars + maskedList.add(actualValue.toString().replaceAll(".", "*")); + } + + return maskedList.toString(); + } +} diff --git a/rest-client/src/test/java/org/zanata/rest/client/FileResourceClientTest.java b/rest-client/src/test/java/org/zanata/rest/client/FileResourceClientTest.java new file mode 100644 index 00000000..7e310453 --- /dev/null +++ b/rest-client/src/test/java/org/zanata/rest/client/FileResourceClientTest.java @@ -0,0 +1,144 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.rest.client; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.apache.commons.codec.binary.Hex; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zanata.common.ProjectType; +import org.zanata.rest.DocumentFileUploadForm; +import org.zanata.rest.StringSet; +import org.zanata.rest.dto.ChunkUploadResponse; +import org.zanata.rest.dto.VersionInfo; + +import static org.junit.Assert.*; + +public class FileResourceClientTest { + private static final Logger log = + LoggerFactory.getLogger(FileResourceClientTest.class); + private FileResourceClient fileResourceClient; + + @Before + public void setUp() throws URISyntaxException { + RestClientFactory factory = + new RestClientFactory(new URI("http://localhost:8180/zanata/"), + "admin", + "b6d7044e9ee3b2447c28fb7c50d86d98", new VersionInfo( + "3.6.0-SNAPSHOT", "unknown", "unknown"), true, true); + fileResourceClient = new FileResourceClient(factory); + } + + + + @Test + public void testServerAcceptedType() { + StringSet serverAcceptedTypes = fileResourceClient + .acceptedFileTypes(); + + + assertThat(serverAcceptedTypes, Matchers.containsInAnyOrder( + ProjectType.getSupportedSourceFileTypes(ProjectType.File) + .toArray())); + } + + @Test + public void testSourceFileUpload() throws Exception { + + + DocumentFileUploadForm uploadForm = new DocumentFileUploadForm(); + File source = new File( + Thread.currentThread().getContextClassLoader() + .getResource("test-odt.odt").getFile()); + FileInputStream fileInputStream = new FileInputStream(source); + + uploadForm.setFileStream(fileInputStream); + uploadForm.setFileType("odt"); + uploadForm.setHash(calculateFileHash(source)); + uploadForm.setFirst(true); + uploadForm.setLast(true); + uploadForm.setSize(source.length()); + ChunkUploadResponse uploadResponse = fileResourceClient + .uploadSourceFile("about-fedora", "master", + "test.odt", + uploadForm); + log.info("response: {}", uploadResponse); + assertThat(uploadResponse.getAcceptedChunks(), Matchers.equalTo(1)); + } + + @Test + public void testTranslationFileUpload() throws Exception { + DocumentFileUploadForm uploadForm = new DocumentFileUploadForm(); + File source = new File( + Thread.currentThread().getContextClassLoader() + .getResource("zh-CN/test-odt.odt").getFile()); + FileInputStream fileInputStream = new FileInputStream(source); + + uploadForm.setFileStream(fileInputStream); + uploadForm.setFileType("odt"); + uploadForm.setHash(calculateFileHash(source)); + uploadForm.setFirst(true); + uploadForm.setLast(true); + uploadForm.setSize(source.length()); + ChunkUploadResponse uploadResponse = fileResourceClient + .uploadTranslationFile("about-fedora", "master", + "zh", + "test.odt", "auto", + uploadForm); + log.info("response: {}", uploadResponse); + assertThat(uploadResponse.getAcceptedChunks(), Matchers.equalTo(1)); + } + + private String calculateFileHash(File srcFile) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + InputStream fileStream = new FileInputStream(srcFile); + try { + fileStream = new DigestInputStream(fileStream, md); + byte[] buffer = new byte[256]; + while (fileStream.read(buffer) > 0) { + // continue + } + } finally { + fileStream.close(); + } + String md5hash = new String(Hex.encodeHex(md.digest())); + return md5hash; + } catch (NoSuchAlgorithmException | IOException e) { + throw new RuntimeException(e); + } + } + + +} \ No newline at end of file diff --git a/rest-client/src/test/java/org/zanata/rest/client/RestClientFactoryTest.java b/rest-client/src/test/java/org/zanata/rest/client/RestClientFactoryTest.java new file mode 100644 index 00000000..ddbf17b2 --- /dev/null +++ b/rest-client/src/test/java/org/zanata/rest/client/RestClientFactoryTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.rest.client; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.zanata.rest.client.RestClientFactory; +import org.zanata.rest.dto.VersionInfo; + +public class RestClientFactoryTest { + + private RestClientFactory restClientFactory; + + @Before + public void setUp() throws URISyntaxException { + restClientFactory = + new RestClientFactory(new URI("http://localhost:8180/zanata/"), + "admin", + "b6d7044e9ee3b2447c28fb7c50d86d98", new VersionInfo( + "3.6.0-SNAPSHOT", "unknown", "unknown"), true, true); + } + + @Test + public void testGetVersion() { + VersionInfo serverVersionInfo = restClientFactory.getServerVersionInfo(); + + MatcherAssert.assertThat(serverVersionInfo.getVersionNo(), + Matchers.equalTo("3.6.0-SNAPSHOT")); + } + +} \ No newline at end of file diff --git a/rest-client/src/test/java/org/zanata/rest/client/SourceDocResourceClientTest.java b/rest-client/src/test/java/org/zanata/rest/client/SourceDocResourceClientTest.java new file mode 100644 index 00000000..2f5c0afc --- /dev/null +++ b/rest-client/src/test/java/org/zanata/rest/client/SourceDocResourceClientTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.rest.client; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; +import org.zanata.rest.dto.VersionInfo; +import org.zanata.rest.dto.resource.ResourceMeta; + +import static org.junit.Assert.*; + +public class SourceDocResourceClientTest { + + private SourceDocResourceClient client; + + @Before + public void setUp() throws URISyntaxException { + RestClientFactory factory = + new RestClientFactory(new URI("http://localhost:8080/zanata/"), + "admin", + "b6d7044e9ee3b2447c28fb7c50d86d98", new VersionInfo( + "3.6.0-SNAPSHOT", "unknown", "unknown"), true, true); + client = new SourceDocResourceClient(factory, "about-fedora", "master"); + } + + @Test + public void testGetResourceMeta() { + List resourceMeta = client.getResourceMeta(null); + + assertThat(resourceMeta, Matchers.hasSize(5)); + } + +} \ No newline at end of file diff --git a/rest-client/src/test/java/org/zanata/rest/client/StatisticsResourceClientTest.java b/rest-client/src/test/java/org/zanata/rest/client/StatisticsResourceClientTest.java new file mode 100644 index 00000000..8fe331d2 --- /dev/null +++ b/rest-client/src/test/java/org/zanata/rest/client/StatisticsResourceClientTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.rest.client; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zanata.rest.dto.VersionInfo; +import org.zanata.rest.dto.stats.ContainerTranslationStatistics; + +import static org.junit.Assert.*; + +public class StatisticsResourceClientTest { + private static final Logger log = + LoggerFactory.getLogger(StatisticsResourceClientTest.class); + private StatisticsResourceClient client; + + @Before + public void setUp() throws URISyntaxException { + RestClientFactory factory = + new RestClientFactory(new URI("https://translate-stg.zanata.org/zanata/"), + "pahuang", + "bdf6cfd644f08569a13c88f76af381a6", new VersionInfo( + "3.6.0-SNAPSHOT", "unknown", "unknown"), true, true); + client = new StatisticsResourceClient(factory); + } + + @Test + public void testGetStatistics() { + ContainerTranslationStatistics statistics = + client.getStatistics("pahuang-test", "master", true, true, + new String[]{ "de-DE", "de", "zh-CN" }); + + log.info("{}", statistics); + } + +} \ No newline at end of file diff --git a/rest-client/src/test/resources/log4j.xml b/rest-client/src/test/resources/log4j.xml new file mode 100644 index 00000000..8a309e84 --- /dev/null +++ b/rest-client/src/test/resources/log4j.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + diff --git a/rest-client/src/test/resources/test-odt.odt b/rest-client/src/test/resources/test-odt.odt new file mode 100644 index 00000000..ba7e10ec Binary files /dev/null and b/rest-client/src/test/resources/test-odt.odt differ diff --git a/rest-client/src/test/resources/zh-CN/test-odt.odt b/rest-client/src/test/resources/zh-CN/test-odt.odt new file mode 100644 index 00000000..5c5d4ad8 Binary files /dev/null and b/rest-client/src/test/resources/zh-CN/test-odt.odt differ diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/PutProjectCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/PutProjectCommand.java index 4f1fc468..07ac01b6 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/PutProjectCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/PutProjectCommand.java @@ -4,6 +4,7 @@ import java.net.URI; import java.net.URISyntaxException; +import javax.ws.rs.core.Response; import javax.xml.bind.JAXBException; import org.jboss.resteasy.client.ClientResponse; @@ -12,6 +13,7 @@ import org.zanata.rest.client.ClientUtility; import org.zanata.rest.client.IProjectResource; import org.zanata.rest.dto.Project; +import org.zanata.rest.service.ProjectResource; /** * @author Sean Flanigan @@ -45,11 +47,11 @@ public void run() throws JAXBException, URISyntaxException, IOException, log.debug("{}", project); // send project to rest api - IProjectResource projResource = + ProjectResource projResource = getRequestFactory().getProject(getOpts().getProjectSlug()); URI uri = getRequestFactory().getProjectURI(getOpts().getProjectSlug()); - ClientResponse response = projResource.put(project); + Response response = projResource.put(project); ClientUtility.checkResult(response, uri); } } diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/PutVersionCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/PutVersionCommand.java index 05335308..1d97ccd0 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/PutVersionCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/PutVersionCommand.java @@ -2,12 +2,15 @@ import java.net.URI; +import javax.ws.rs.core.Response; + import org.jboss.resteasy.client.ClientResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.zanata.rest.client.ClientUtility; import org.zanata.rest.client.IProjectIterationResource; import org.zanata.rest.dto.ProjectIteration; +import org.zanata.rest.service.ProjectIterationResource; /** * @author Sean Flanigan @@ -35,7 +38,7 @@ public void run() throws Exception { } log.debug("{}", version); - IProjectIterationResource iterResource = + ProjectIterationResource iterResource = getRequestFactory().getProjectIteration( getOpts().getVersionProject(), getOpts().getVersionSlug()); @@ -43,7 +46,7 @@ public void run() throws Exception { getRequestFactory().getProjectIterationURI( getOpts().getVersionProject(), getOpts().getVersionSlug()); - ClientResponse response = iterResource.put(version); + Response response = iterResource.put(version); ClientUtility.checkResult(response, uri); } diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/init/InitCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/init/InitCommand.java index 53a2d927..d61bb028 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/init/InitCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/init/InitCommand.java @@ -31,6 +31,7 @@ import java.io.IOException; import java.net.URL; +import javax.ws.rs.core.Response; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; @@ -236,7 +237,7 @@ public ZanataProxyFactory getRequestFactory() { @VisibleForTesting protected void downloadZanataXml(String projectId, String iterationId, File configFileDest) throws IOException { - ClientResponse response = + Response response = getRequestFactory().getProjectIteration(projectId, iterationId) .sampleConfiguration(); if (response.getStatus() >= 399) { @@ -249,7 +250,7 @@ protected void downloadZanataXml(String projectId, String iterationId, "Can not create %s. Make sure permission is writable.", configFileDest); - String content = (String) response.getEntity(String.class); + String content = response.getEntity().toString(); log.debug("project config from the server:\n{}", content); FileUtils.write(configFileDest, content, UTF_8); getOpts().setProjectConfig(configFileDest); @@ -281,6 +282,14 @@ protected void writeToConfig(File srcDir, String includes, String excludes, getOpts().getProjectConfig()); } + public static void offerRetryOnServerError(Response response, + ConsoleInteractor consoleInteractor) { + consoleInteractor.printfln(Warning, _("server.error"), + response.getEntity().toString()); + consoleInteractor.printf(Question, _("server.error.try.again")); + consoleInteractor.expectYes(); + } + // we don't have all mandatory information yet private static class MockZanataProxyFactory extends ZanataProxyFactory { private static final MockZanataProxyFactory mockFactory = diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/init/ProjectIterationPrompt.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/init/ProjectIterationPrompt.java index ae81bda1..c76aecf5 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/init/ProjectIterationPrompt.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/init/ProjectIterationPrompt.java @@ -22,6 +22,8 @@ import java.util.List; +import javax.ws.rs.core.Response; + import org.jboss.resteasy.client.ClientResponse; import org.zanata.client.commands.ConsoleInteractor; import org.zanata.common.EntityStatus; @@ -75,7 +77,7 @@ public void selectOrCreateNewVersion() { @VisibleForTesting protected void selectVersion() { Project project = proxyFactory.getProject(opts.getProj()).get() - .getEntity(Project.class); + .readEntity(Project.class); consoleInteractor.printfln(_("available.versions"), project.getName()); int oneBasedIndex = 1; List versionIndexes = Lists.newArrayList(); @@ -104,14 +106,13 @@ protected void createNewVersion() { String versionId = consoleInteractor.expectAnyAnswer(); ProjectIteration iteration = new ProjectIteration(versionId); iteration.setProjectType(opts.getProjectType()); - ClientResponse response = + Response response = proxyFactory.getProjectIteration(opts.getProj(), versionId) .put(iteration); if (response.getStatus() >= 399) { InitCommand.offerRetryOnServerError(response, consoleInteractor); createNewVersion(); } - response.releaseConnection(); opts.setProjectVersion(versionId); consoleInteractor.printfln(Confirmation, _("project.version.created")); diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/init/ProjectPrompt.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/init/ProjectPrompt.java index e707b151..05208568 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/init/ProjectPrompt.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/init/ProjectPrompt.java @@ -23,6 +23,8 @@ import java.util.Collections; import java.util.List; +import javax.ws.rs.core.Response; + import org.jboss.resteasy.client.ClientResponse; import org.zanata.client.commands.ConsoleInteractor; import org.zanata.common.EntityStatus; @@ -197,13 +199,12 @@ protected void createNewProject() { String projectType = consoleInteractor.expectAnswerWithRetry( AnswerValidatorImpl.expect(projectTypeList)); - ClientResponse response = proxyFactory.getProject(projectId) + Response response = proxyFactory.getProject(projectId) .put(new Project(projectId, projectName, projectType)); if (response.getStatus() >= 399) { InitCommand.offerRetryOnServerError(response, consoleInteractor); createNewProject(); } - response.releaseConnection(); consoleInteractor.printfln(Confirmation, _("project.created")); opts.setProj(projectId); opts.setProjectType(projectType); diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/pull/RawPullCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/pull/RawPullCommand.java index efaaa4d7..ec4f8453 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/pull/RawPullCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/pull/RawPullCommand.java @@ -57,7 +57,7 @@ public class RawPullCommand extends PushPullCommand { private static final Logger log = LoggerFactory .getLogger(RawPullCommand.class); - private IFileResource fileResource; + private FileResource fileResource; public RawPullCommand(PullOptions opts) { super(opts); @@ -156,21 +156,20 @@ public void run() throws IOException { String localDocName = unqualifiedDocName(qualifiedDocName); if (pullSrc) { - ClientResponse response = + Response response = fileResource.downloadSourceFile( getOpts().getProj(), getOpts() .getProjectVersion(), FileResource.FILETYPE_RAW_SOURCE_DOCUMENT, qualifiedDocName); - if (response.getResponseStatus() == Status.NOT_FOUND) { + if (response.getStatusInfo() == Status.NOT_FOUND) { log.warn( "No source document file is available for [{}]. Skipping.", qualifiedDocName); } else { ClientUtility.checkResult(response, uri); InputStream srcDoc = - (InputStream) response - .getEntity(InputStream.class); + response.readEntity(InputStream.class); if (srcDoc != null) { try { strat.writeSrcFile(localDocName, srcDoc); @@ -193,20 +192,19 @@ public void run() throws IOException { for (LocaleMapping locMapping : locales) { LocaleId locale = new LocaleId(locMapping.getLocale()); - ClientResponse response = + Response response = fileResource.downloadTranslationFile(getOpts() .getProj(), getOpts() .getProjectVersion(), locale.getId(), fileExtension, qualifiedDocName); - if (response.getResponseStatus() == Response.Status.NOT_FOUND) { + if (response.getStatusInfo() == Response.Status.NOT_FOUND) { log.info( "No translation document file found in locale {} for document [{}]", locale, qualifiedDocName); } else { ClientUtility.checkResult(response, uri); InputStream transDoc = - (InputStream) response - .getEntity(InputStream.class); + response.readEntity(InputStream.class); if (transDoc != null) { try { strat.writeTransFile(localDocName, locMapping, diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/push/RawPushCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/push/RawPushCommand.java index 43f53d67..a82d6c4a 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/push/RawPushCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/push/RawPushCommand.java @@ -38,6 +38,8 @@ import java.util.SortedSet; import java.util.TreeSet; +import javax.ws.rs.core.Response; + import com.google.common.collect.ImmutableList; import org.apache.commons.codec.binary.Hex; import org.jboss.resteasy.client.ClientResponse; @@ -56,6 +58,7 @@ import org.zanata.rest.client.ITranslatedDocResource; import org.zanata.rest.client.ZanataProxyFactory; import org.zanata.rest.dto.ChunkUploadResponse; +import org.zanata.rest.service.FileResource; /** * Command to send files directly to the server without parsing on the client. @@ -68,7 +71,7 @@ public class RawPushCommand extends PushPullCommand { private static final Logger log = LoggerFactory .getLogger(PushCommand.class); - protected final IFileResource fileResource; + protected final FileResource fileResource; public RawPushCommand(PushOptions opts) { super(opts); @@ -107,9 +110,10 @@ public void run() throws IOException { ImmutableList.Builder builder = ImmutableList.builder(); - ClientResponse response = fileResource.acceptedFileTypes(); + Response response = fileResource.acceptedFileTypes(); @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") - StringSet serverAcceptedTypes = new StringSet(response.getEntity()); + StringSet serverAcceptedTypes = new StringSet( + response.readEntity(String.class)); for (String type : getOpts().getFileTypes()) { if (serverAcceptedTypes.contains(type)) { builder.add(type); @@ -303,7 +307,7 @@ private void pushDocumentToServer(String docId, String fileType, DocumentFileUploadForm uploadForm = generateUploadForm(true, true, fileType, md5hash, docFile.length(), fileStream); - ClientResponse response = + Response response = uploadDocumentPart(docId, locale, uploadForm); checkChunkUploadStatus(response); } @@ -312,7 +316,7 @@ private void pushDocumentToServer(String docId, String fileType, getOpts().getChunkSize())) { log.info(" transmitting file [{}] as {} chunks", docFile.getAbsolutePath(), chunker.totalChunks()); - ClientResponse uploadResponse; + Response uploadResponse; DocumentFileUploadForm uploadForm; Long uploadId = null; @@ -334,7 +338,8 @@ private void pushDocumentToServer(String docId, String fileType, uploadDocumentPart(docId, locale, uploadForm); checkChunkUploadStatus(uploadResponse); if (isFirst) { - uploadId = uploadResponse.getEntity().getUploadId(); + uploadId = uploadResponse.readEntity( + ChunkUploadResponse.class).getUploadId(); if (uploadId == null) { throw new RuntimeException( "server did not return upload id"); @@ -349,11 +354,12 @@ private void pushDocumentToServer(String docId, String fileType, } private void checkChunkUploadStatus( - ClientResponse uploadResponse) { + Response uploadResponse) { if (uploadResponse.getStatus() >= 300) { throw new RuntimeException("Server returned error status: " + uploadResponse.getStatus() + ". Error message: " - + uploadResponse.getEntity().getErrorMessage()); + + uploadResponse.readEntity(ChunkUploadResponse.class) + .getErrorMessage()); } } @@ -370,10 +376,10 @@ private DocumentFileUploadForm generateUploadForm(boolean isFirst, return uploadForm; } - private ClientResponse uploadDocumentPart( + private Response uploadDocumentPart( String docName, String locale, DocumentFileUploadForm uploadForm) { ConsoleUtils.startProgressFeedback(); - ClientResponse response; + Response response; if (locale == null) { response = fileResource.uploadSourceFile(getOpts().getProj(), diff --git a/zanata-client-commands/src/test/java/org/zanata/client/TestProjectGenerator.java b/zanata-client-commands/src/test/java/org/zanata/client/TestProjectGenerator.java index 7d5a95a8..decce46a 100644 --- a/zanata-client-commands/src/test/java/org/zanata/client/TestProjectGenerator.java +++ b/zanata-client-commands/src/test/java/org/zanata/client/TestProjectGenerator.java @@ -2,7 +2,9 @@ import java.io.File; import java.io.FilenameFilter; +import java.net.MalformedURLException; import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.util.Map; @@ -17,7 +19,10 @@ import org.zanata.rest.client.ZanataProxyFactory; import org.zanata.rest.dto.Project; import org.zanata.rest.dto.ProjectIteration; +import org.zanata.rest.service.ProjectIterationResource; +import org.zanata.rest.service.ProjectResource; import com.google.common.base.Preconditions; +import com.google.common.base.Throwables; import com.google.common.collect.ImmutableMap; /** @@ -100,11 +105,11 @@ public void ensureProjectOnServer(ConfigurableProjectOptions opts, String iterationSlug = iteration.getId(); // create project and version - IProjectResource projectResource = + ProjectResource projectResource = requestFactory.getProject(projectSlug); ClientUtility.checkResultAndReleaseConnection( projectResource.put(projectDTO)); - IProjectIterationResource iterationResource = + ProjectIterationResource iterationResource = requestFactory.getProjectIteration(projectSlug, iterationSlug); ClientUtility.checkResultAndReleaseConnection( iterationResource.put(iteration)); @@ -161,6 +166,15 @@ public String getUrl() { return url; } + public URL getURL() { + try { + return new URI(url).toURL(); + } + catch (MalformedURLException | URISyntaxException e) { + throw Throwables.propagate(e); + } + } + public String getUsername() { return username; } diff --git a/zanata-client-commands/src/test/java/org/zanata/client/integraion/FileProjectITCase.java b/zanata-client-commands/src/test/java/org/zanata/client/integraion/FileProjectITCase.java new file mode 100644 index 00000000..fadb401b --- /dev/null +++ b/zanata-client-commands/src/test/java/org/zanata/client/integraion/FileProjectITCase.java @@ -0,0 +1,87 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.client.integraion; + +import java.io.File; +import java.io.IOException; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.zanata.client.TestProjectGenerator; +import org.zanata.client.commands.ConfigurableProjectOptions; +import org.zanata.client.commands.push.PushOptionsImpl; +import org.zanata.client.commands.push.RawPushCommand; +import org.zanata.client.config.LocaleList; +import org.zanata.client.config.LocaleMapping; +import org.zanata.common.ProjectType; + +/** + * @author Patrick Huang + * pahuang@redhat.com + */ +public class FileProjectITCase { + private static final Logger log = + LoggerFactory.getLogger(FileProjectITCase.class); + @Rule + public TemporaryFolder tempFolder = new TemporaryFolder(); + + private TestProjectGenerator testProjectGenerator = + new TestProjectGenerator(); + private PushOptionsImpl opts; + + @Before + public void setUp() throws Exception { + opts = new PushOptionsImpl(); + TestProjectGenerator.ServerInstance instance = + TestProjectGenerator.ServerInstance.FunctionalTestCargo; + opts.setUrl(instance.getURL()); + opts.setUsername(instance.getUsername()); + opts.setKey(instance.getKey()); + testProjectGenerator.ensureProjectOnServer(opts, + ProjectType.File, instance); + opts.setLocaleMapList(new LocaleList()); + opts.getLocaleMapList().add(new LocaleMapping("zh-CN")); + opts.setBatchMode(true); + } + + @Test + public void manualTest() throws IOException { + File baseDir = + testProjectGenerator.getProjectBaseDir(ProjectType.File); + log.debug("testing project is at: {}", baseDir); + opts.setFileTypes("odt,ods"); + opts.setSrcDir(new File(baseDir, "src")); + opts.setTransDir(baseDir); + opts.setProj(testProjectGenerator.sampleProjectSlug(baseDir)); + opts.setProjectVersion(testProjectGenerator.sampleIterationSlug()); + opts.setProjectType("file"); + opts.setFileTypes("odt"); + + RawPushCommand pushCommand = new RawPushCommand(opts); + + pushCommand.run(); + } +} diff --git a/zanata-client-commands/src/test/resources/log4j.xml b/zanata-client-commands/src/test/resources/log4j.xml new file mode 100644 index 00000000..8a309e84 --- /dev/null +++ b/zanata-client-commands/src/test/resources/log4j.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + diff --git a/zanata-rest-client/pom.xml b/zanata-rest-client/pom.xml index 0559ec2a..ac6fe372 100644 --- a/zanata-rest-client/pom.xml +++ b/zanata-rest-client/pom.xml @@ -23,6 +23,24 @@ org.zanata zanata-common-api + + + org.jboss.resteasy + resteasy-jaxrs + + + org.jboss.resteasy + resteasy-jaxb-provider + + + org.jboss.resteasy + jaxrs-api + + + org.jboss.resteasy + resteasy-multipart-provider + + @@ -30,27 +48,44 @@ junit test + + + + + + + + + + + + + + + + + + + + + + - org.jboss.resteasy - jaxrs-api - ${resteasy.version} + com.sun.jersey + jersey-core + 1.17.1 - - org.jboss.resteasy - resteasy-jaxrs - - - net.jcip - jcip-annotations - - + com.sun.jersey + jersey-client + 1.17.1 - org.jboss.resteasy - resteasy-client - ${resteasy.version} + com.sun.jersey.contribs + jersey-multipart + 1.17.1 + commons-beanutils commons-beanutils diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderDecorator.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderDecorator.java index 805f7ab5..ee0981d2 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderDecorator.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderDecorator.java @@ -1,18 +1,20 @@ package org.zanata.rest.client; +import java.io.IOException; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.Provider; -import org.jboss.resteasy.annotations.interception.ClientInterceptor; -import org.jboss.resteasy.client.ClientResponse; -import org.jboss.resteasy.spi.interception.ClientExecutionContext; -import org.jboss.resteasy.spi.interception.ClientExecutionInterceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.zanata.rest.RestConstant; +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.ClientRequest; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.filter.ClientFilter; @Provider -@ClientInterceptor -public class ApiKeyHeaderDecorator implements ClientExecutionInterceptor { +//@ClientInterceptor +public class ApiKeyHeaderDecorator extends ClientFilter { private static Logger log = LoggerFactory .getLogger(ApiKeyHeaderDecorator.class); private String apiKey; @@ -28,36 +30,14 @@ public ApiKeyHeaderDecorator(String username, String apiKey, String ver) { this.ver = ver; } - @SuppressWarnings("rawtypes") @Override - public ClientResponse execute(ClientExecutionContext ctx) throws Exception { - ctx.getRequest().getHeadersAsObjects() - .add(RestConstant.HEADER_USERNAME, username); - ctx.getRequest().getHeadersAsObjects() - .add(RestConstant.HEADER_API_KEY, apiKey); - ctx.getRequest().getHeadersAsObjects() - .add(RestConstant.HEADER_VERSION_NO, ver); - try { - return ctx.proceed(); - } catch (Error e) { - // NB Seam/RestEasy doesn't log these exceptions fully for some - // reason - log.warn("error processing request", e); - throw e; - } catch (Exception e) { - // NB Seam/RestEasy doesn't log these exceptions fully for some - // reason - log.warn("exception processing request", e); - throw e; - } - } - - public String getApiKey() { - return apiKey; - } - - public void setApiKey(String apiKey) { - this.apiKey = apiKey; + public ClientResponse handle(ClientRequest cr) + throws ClientHandlerException { + MultivaluedMap headers = cr.getHeaders(); + headers.add(RestConstant.HEADER_USERNAME, username); + headers.add(RestConstant.HEADER_API_KEY, apiKey); + headers.add(RestConstant.HEADER_VERSION_NO, ver); + return getNext().handle(cr); } public String getUsername() { diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/ClientUtility.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/ClientUtility.java index fef8f53f..200e2952 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/ClientUtility.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/ClientUtility.java @@ -5,15 +5,14 @@ import javax.ws.rs.core.Response; -import org.jboss.resteasy.client.ClientResponse; -import org.jboss.resteasy.client.core.BaseClientResponse; +import com.sun.jersey.api.client.ClientResponse; public class ClientUtility { - public static void checkResult(ClientResponse response) { + public static void checkResult(ClientResponse response) { checkResult(response, null); } - public static void checkResult(ClientResponse response, URI uri) { + public static void checkResult(ClientResponse response, URI uri) { if (response.getResponseStatus() == Response.Status.UNAUTHORIZED) { throw new RuntimeException("Incorrect username/password"); } else if (response.getResponseStatus() == Response.Status.SERVICE_UNAVAILABLE) { @@ -23,13 +22,13 @@ public static void checkResult(ClientResponse response, URI uri) { String annotString = ""; String uriString = ""; String entity = ""; - if (response instanceof BaseClientResponse) { - BaseClientResponse resp = (BaseClientResponse) response; - annotString = - ", annotations: " - + Arrays.asList(resp.getAnnotations()) - .toString(); - } +// if (response instanceof BaseClientResponse) { +// BaseClientResponse resp = (BaseClientResponse) response; +// annotString = +// ", annotations: " +// + Arrays.asList(resp.getAnnotations()) +// .toString(); +// } if (uri != null) { uriString = ", uri: " + uri; } @@ -50,8 +49,52 @@ public static void checkResult(ClientResponse response, URI uri) { } public static void checkResultAndReleaseConnection( - ClientResponse clientResponse) { + ClientResponse clientResponse) { checkResult(clientResponse, null); - clientResponse.releaseConnection(); +// clientResponse.releaseConnection(); + } + + public static void checkResult(Response response) { + checkResult(response, null); + } + + public static void checkResult(Response response, URI uri) { + if (response.getStatus() == Response.Status.UNAUTHORIZED.getStatusCode()) { + throw new RuntimeException("Incorrect username/password"); + } else if (response.getStatus() == Response.Status.SERVICE_UNAVAILABLE.getStatusCode()) { + throw new RuntimeException("Service is currently unavailable. " + + "Please check outage notification or try again later."); + } else if (response.getStatus() >= 399) { + String annotString = ""; + String uriString = ""; + String entity = ""; +// if (response instanceof BaseClientResponse) { +// BaseClientResponse resp = (BaseClientResponse) response; +// annotString = +// ", annotations: " +// + Arrays.asList(resp.getAnnotations()) +// .toString(); +// } + if (uri != null) { + uriString = ", uri: " + uri; + } + try { + entity = ": " + response.getEntity(); + } finally { + // ignore + } + String msg = + "operation returned " + + response.getStatus() + + " (" + + Response.Status.fromStatusCode(response + .getStatus()) + ")" + entity + uriString + + annotString; + throw new RuntimeException(msg); + } + } + + public static void checkResultAndReleaseConnection(Response response) { + checkResult(response); } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/TraceDebugInterceptor.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/TraceDebugInterceptor.java index ca9e00bf..bfb608b5 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/TraceDebugInterceptor.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/TraceDebugInterceptor.java @@ -20,18 +20,24 @@ */ package org.zanata.rest.client; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +//import javax.ws.rs.client.ClientRequestContext; +//import javax.ws.rs.client.ClientRequestFilter; +//import javax.ws.rs.client.ClientResponseContext; +//import javax.ws.rs.client.ClientResponseFilter; import javax.ws.rs.ext.Provider; -import org.jboss.resteasy.annotations.interception.ClientInterceptor; -import org.jboss.resteasy.client.ClientResponse; -import org.jboss.resteasy.spi.interception.ClientExecutionContext; -import org.jboss.resteasy.spi.interception.ClientExecutionInterceptor; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.zanata.rest.RestConstant; +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.ClientRequest; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.filter.ClientFilter; /** * Performs logging of Resteasy Requests on the client side. This interceptor @@ -43,8 +49,8 @@ * */ @Provider -@ClientInterceptor -public class TraceDebugInterceptor implements ClientExecutionInterceptor { +//@ClientInterceptor +public class TraceDebugInterceptor extends ClientFilter { private static final Logger log = LoggerFactory .getLogger(TraceDebugInterceptor.class); @@ -55,68 +61,112 @@ public TraceDebugInterceptor() { this(true); } - public TraceDebugInterceptor(boolean logHttp) { - this.logHttp = logHttp; - } - - private void log(String msg) { - if (logHttp) { - log.info(msg); - } else { - log.trace(msg); - } - } - - @SuppressWarnings("rawtypes") @Override - public ClientResponse execute(ClientExecutionContext ctx) throws Exception { + public ClientResponse handle(ClientRequest cr) + throws ClientHandlerException { if (!logHttp && !log.isTraceEnabled()) { - return ctx.proceed(); + return getNext().handle(cr); } - - log(">> REST Request: " + ctx.getRequest().getHttpMethod() + " => " - + ctx.getRequest().getUri()); + log(">> REST Request: " + cr.getMethod() + " => " + + cr.getURI()); // Log before sending a request - for (String key : ctx.getRequest().getHeaders().keySet()) { + for (String key : cr.getHeaders().keySet()) { String headerVal = - ctx.getRequest().getHeaders().get(key).toString(); + cr.getHeaders().get(key).toString(); if (key.equals(RestConstant.HEADER_API_KEY)) { headerVal = - this.maskHeaderValues(ctx.getRequest().getHeaders() - .get(key)); + this.maskHeaderValues( + cr.getHeaders() + .get(key)); } log(">> Header: " + key + " = " + headerVal); } - log(">> Body: " + ctx.getRequest().getBody()); - ClientResponse result = ctx.proceed(); + ClientResponse response = getNext().handle(cr); + log(">> Body: " + response.getEntity(String.class)); + +// ClientResponse result = ctx.proceed(); // log after a response has been received - log("<< REST Response: " + result.getResponseStatus().getStatusCode() - + ":" + result.getResponseStatus()); - for (String key : result.getHeaders().keySet()) { - log("<< Header: " + key + " = " + result.getHeaders().get(key)); + log("<< REST Response: " + response.getStatus() + + ":" + response.getClientResponseStatus()); + for (String key : response.getHeaders().keySet()) { + log("<< Header: " + key + " = " + + response.getHeaders().get(key)); } + return response; + } - return result; + public TraceDebugInterceptor(boolean logHttp) { + this.logHttp = logHttp; + } + + private void log(String msg) { + if (logHttp) { + log.info(msg); + } else { + log.trace(msg); + } } /** * Masks a list of header values so they are not displayed as clear text in * the logs. */ - private String maskHeaderValues(List headerValues) { + private String maskHeaderValues(List headerValues) { List maskedList = new ArrayList(headerValues.size()); - for (String actualValue : headerValues) { - maskedList.add(actualValue.replaceAll(".", "*")); // mask all + for (Object actualValue : headerValues) { + maskedList.add(actualValue.toString().replaceAll(".", "*")); // mask all // characters with // stars } return maskedList.toString(); } - +// +// @Override +// public void filter(ClientRequestContext clientRequestContext) +// throws IOException { +// if (!logHttp && !log.isTraceEnabled()) { +// return; +// } +// +// log(">> REST Request: " + clientRequestContext.getMethod() + " => " +// + clientRequestContext.getUri()); +// +// // Log before sending a request +// for (String key : clientRequestContext.getHeaders().keySet()) { +// String headerVal = +// clientRequestContext.getHeaders().get(key).toString(); +// if (key.equals(RestConstant.HEADER_API_KEY)) { +// headerVal = +// this.maskHeaderValues( +// clientRequestContext.getStringHeaders() +// .get(key)); +// } +// +// log(">> Header: " + key + " = " + headerVal); +// } +// +// } +// +// @Override +// public void filter(ClientRequestContext clientRequestContext, +// ClientResponseContext clientResponseContext) throws IOException { +// log(">> Body: " + clientResponseContext.getEntityStream()); +// +//// ClientResponse result = ctx.proceed(); +// +// // log after a response has been received +// log("<< REST Response: " + clientRequestContext.getHeaderString("status") +// + ":"); +// for (String key : clientRequestContext.getHeaders().keySet()) { +// log("<< Header: " + key + " = " + +// clientRequestContext.getHeaderString(key)); +// } +// +// } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/ZanataProxyFactory.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/ZanataProxyFactory.java index e4e126fa..c4ed61c2 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/ZanataProxyFactory.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/ZanataProxyFactory.java @@ -1,50 +1,30 @@ package org.zanata.rest.client; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.ConnectException; -import java.net.InetSocketAddress; import java.net.MalformedURLException; -import java.net.Socket; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.net.UnknownHostException; -import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; +import javax.ws.rs.core.Response; -import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.lang.SystemUtils; -import org.apache.http.HttpHost; -import org.apache.http.client.HttpClient; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.ConnectTimeoutException; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.conn.ssl.X509HostnameVerifier; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.HttpContext; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; -import org.jboss.resteasy.client.ClientExecutor; -import org.jboss.resteasy.client.ClientRequestFactory; -import org.jboss.resteasy.client.ClientResponse; -import org.jboss.resteasy.client.core.ClientInterceptorRepository; -import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor; -import org.jboss.resteasy.client.exception.ResteasyIOException; -import org.jboss.resteasy.plugins.providers.RegisterBuiltin; -import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.zanata.rest.DocumentFileUploadForm; import org.zanata.rest.RestConstant; import org.zanata.rest.dto.VersionInfo; -import com.google.common.base.Throwables; +import org.zanata.rest.service.FileResource; +import org.zanata.rest.service.ProjectIterationResource; +import org.zanata.rest.service.ProjectResource; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import com.sun.jersey.multipart.impl.MultiPartWriter; // TODO fix deprecation warnings public class ZanataProxyFactory implements ITranslationResourcesFactory { @@ -52,21 +32,19 @@ public class ZanataProxyFactory implements ITranslationResourcesFactory { .getLogger(ZanataProxyFactory.class); static { - ResteasyProviderFactory instance = - ResteasyProviderFactory.getInstance(); - RegisterBuiltin.register(instance); if (!SystemUtils.isJavaVersionAtLeast(1.7f)) { log.warn("Please upgrade to Java 1.7 or later, or you may have trouble connecting to some secure hosts."); } } + private URI baseURI; private VersionInfo clientApiVersion; private String clientVersion; private String serverVersion; - private ClientRequestFactory crf; + private Client client; /** * see org.zanata.client.commands.init.InitCommand.MockZanataProxyFactory @@ -112,12 +90,16 @@ public ZanataProxyFactory(URI base, String username, String apiKey, public ZanataProxyFactory(URI base, String username, String apiKey, VersionInfo clientApiVersion, boolean logHttp, boolean sslCertDisabled, boolean eagerVersionCheck) { + baseURI = base; this.clientApiVersion = clientApiVersion; - ClientExecutor clientExecutor = createClientExecutor(sslCertDisabled); - - crf = new ClientRequestFactory(clientExecutor, null, fixBase(base)); - crf.setFollowRedirects(true); - registerPrefixInterceptor(new TraceDebugInterceptor(logHttp)); + DefaultClientConfig clientConfig = new DefaultClientConfig(MultiPartWriter.class); + clientConfig.getSingletons().add(new ApiKeyHeaderDecorator(username, apiKey, clientVersion)); + client = Client.create(clientConfig); +// ClientExecutor clientExecutor = createClientExecutor(sslCertDisabled); + +// crf = new ClientRequestFactory(clientExecutor, null, fixBase(base)); +// crf.setFollowRedirects(true); + registerPrefixInterceptor(new TraceDebugInterceptorOld(logHttp)); registerPrefixInterceptor(new ApiKeyHeaderDecorator(username, apiKey, clientApiVersion.getVersionNo())); if (eagerVersionCheck) { @@ -139,20 +121,22 @@ public void performVersionCheck() { } public VersionInfo getServerVersionInfo() { - IVersionResource iversion = createIVersionResource(); - ClientResponse versionResp; - try { - versionResp = iversion.get(); - } catch (ResteasyIOException e) { - Throwable rootCause = Throwables.getRootCause(e); - if (rootCause instanceof ConnectException) { - throw new RuntimeException("Can not connect to the server [" + crf.getBase() + "]. Please check server is up."); - } else { - throw e; - } - } +// IVersionResource iversion = createIVersionResource(); + ClientResponse versionResp = client.resource(getBaseUri()).path("version") + .get(ClientResponse.class); +// ClientResponse versionResp; +// try { +// versionResp = iversion.get(); +// } catch (ResteasyIOException e) { +// Throwable rootCause = Throwables.getRootCause(e); +// if (rootCause instanceof ConnectException) { +// throw new RuntimeException("Can not connect to the server [" + crf.getBase() + "]. Please check server is up."); +// } else { +// throw e; +// } +// } ClientUtility.checkResult(versionResp); - return versionResp.getEntity(); + return versionResp.getEntity(VersionInfo.class); } private void warnMismatchAPIVersion(String clientScm, String serverScm) { @@ -167,77 +151,77 @@ private void warnMismatchAPIVersion(String clientScm, String serverScm) { } } - private static ClientExecutor createClientExecutor(boolean sslCertDisabled) { - try { - final SSLContext sslContext = SSLContext.getInstance("TLS"); - - // Create a trust manager that does not validate certificate chains - // against our server - final TrustManager[] trustAllCerts; - if (sslCertDisabled) { - trustAllCerts = - new TrustManager[]{ new AcceptAllX509TrustManager() }; - } else { - trustAllCerts = null; - } - - sslContext.init(null, trustAllCerts, new SecureRandom()); - - // NB: This factory is a workaround to enable SNI with - // httpcomponents-client 4.2; not needed for 4.3 - SSLSocketFactory factory; - if (sslCertDisabled) { - // avoid triggering the problem described here: - // https://stackoverflow.com/questions/7615645/ssl-handshake-alert-unrecognized-name-error-since-upgrade-to-java-1-7-0 - factory = new SSLSocketFactory(sslContext); - } else { - factory = new SSLSocketFactory(sslContext) { - @Override - public Socket connectSocket(Socket socket, - InetSocketAddress remoteAddress, - InetSocketAddress localAddress, - HttpParams params) - throws IOException, UnknownHostException, - ConnectTimeoutException { - if (socket instanceof SSLSocket) { - try { - PropertyUtils.setProperty(socket, "host", - remoteAddress.getHostName()); - } catch (Exception ex) { - log.warn( - "Unable to enable SNI; you may have trouble connecting to some secure hosts. Please ensure that you are running Java 1.7 or later."); - } - } - return super.connectSocket(socket, remoteAddress, - localAddress, params); - } - }; - } - - HttpClient client = new DefaultHttpClient(); - - if (sslCertDisabled) { - X509HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; - factory.setHostnameVerifier(hostnameVerifier); - } - - ClientConnectionManager manager = client.getConnectionManager(); - manager.getSchemeRegistry().register( - new Scheme("https", 443, factory)); - return new ApacheHttpClient4Executor(client); - - } catch (Exception e) { - log.warn("error creating SSL client", e); - } - return null; - } +// private static ClientExecutor createClientExecutor(boolean sslCertDisabled) { +// try { +// final SSLContext sslContext = SSLContext.getInstance("TLS"); +// +// // Create a trust manager that does not validate certificate chains +// // against our server +// final TrustManager[] trustAllCerts; +// if (sslCertDisabled) { +// trustAllCerts = +// new TrustManager[]{ new AcceptAllX509TrustManager() }; +// } else { +// trustAllCerts = null; +// } +// +// sslContext.init(null, trustAllCerts, new SecureRandom()); +// +// // NB: This factory is a workaround to enable SNI with +// // httpcomponents-client 4.2; not needed for 4.3 +// SSLSocketFactory factory; +// if (sslCertDisabled) { +// // avoid triggering the problem described here: +// // https://stackoverflow.com/questions/7615645/ssl-handshake-alert-unrecognized-name-error-since-upgrade-to-java-1-7-0 +// factory = new SSLSocketFactory(sslContext); +// } else { +// factory = new SSLSocketFactory(sslContext) { +// @Override +// public Socket connectSocket(Socket socket, +// InetSocketAddress remoteAddress, +// InetSocketAddress localAddress, +// HttpParams params) +// throws IOException, UnknownHostException, +// ConnectTimeoutException { +// if (socket instanceof SSLSocket) { +// try { +// PropertyUtils.setProperty(socket, "host", +// remoteAddress.getHostName()); +// } catch (Exception ex) { +// log.warn( +// "Unable to enable SNI; you may have trouble connecting to some secure hosts. Please ensure that you are running Java 1.7 or later."); +// } +// } +// return super.connectSocket(socket, remoteAddress, +// localAddress, params); +// } +// }; +// } +// +// HttpClient client = new DefaultHttpClient(); +// +// if (sslCertDisabled) { +// X509HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER; +// factory.setHostnameVerifier(hostnameVerifier); +// } +// +// ClientConnectionManager manager = client.getConnectionManager(); +// manager.getSchemeRegistry().register( +// new Scheme("https", 443, factory)); +// return new ApacheHttpClient4Executor(client); +// +// } catch (Exception e) { +// log.warn("error creating SSL client", e); +// } +// return null; +// } /** * Returns the Base url to be used for rest Requests. */ private URL getBaseUrl() { try { - return new URL(fixBase(crf.getBase()).toString() + getUrlPrefix()); + return new URL(fixBase(baseURI).toString() + getUrlPrefix()); } catch (MalformedURLException e) { throw new RuntimeException(e); } @@ -257,9 +241,9 @@ protected String getUrlPrefix() { public T createProxy(Class clazz, URI baseUri) { log.debug("{} proxy uri: {}", clazz.getSimpleName(), baseUri); - T proxy = crf.createProxy(clazz, baseUri); +// T proxy = crf.createProxy(clazz, baseUri); // CacheFactory.makeCacheable(proxy); - return proxy; + return null; } /** @@ -312,7 +296,7 @@ public URI getAccountURI(String username) { } } - public IProjectResource getProject(String proj) { + public ProjectResource getProject(String proj) { return createProxy(IProjectResource.class, getProjectURI(proj)); } @@ -327,7 +311,7 @@ public URI getProjectURI(String proj) { } } - public IProjectIterationResource getProjectIteration(String proj, + public ProjectIterationResource getProjectIteration(String proj, String iter) { return createProxy(IProjectIterationResource.class, getProjectIterationURI(proj, iter)); @@ -364,8 +348,65 @@ public ISourceDocResource getSourceDocResource(String projectSlug, getResourceURI(projectSlug, versionSlug)); } - public IFileResource getFileResource() { - return createProxy(IFileResource.class); + public FileResource getFileResource() { + + return new FileResource() { + @Override + public Response acceptedFileTypes() { + String s = client.resource(getBaseUri()) + .path("file").path("accepted_types") + .get(String.class); + return Response.ok().entity(s).build(); + } + + @Override + public Response uploadSourceFile( + String projectSlug, String iterationSlug, String docId, + DocumentFileUploadForm documentFileUploadForm) { + + client.resource(getBaseUri()) + .path("file").path("source").path(projectSlug) + .path(iterationSlug) + .queryParam("docId", docId) + .post(documentFileUploadForm); + return Response.ok().build(); + } + + @Override + public Response uploadTranslationFile(String projectSlug, + String iterationSlug, String locale, String docId, + String mergeType, + DocumentFileUploadForm documentFileUploadForm) { + //TODO implement + throw new UnsupportedOperationException("Implement me!"); + //return null; + } + + @Override + public Response downloadSourceFile(String s, String s2, String s3, + String s4) { + //TODO implement + throw new UnsupportedOperationException("Implement me!"); + //return null; + } + + @Override + public Response downloadTranslationFile(String s, String s2, + String s3, + String s4, String s5) { + //TODO implement + throw new UnsupportedOperationException("Implement me!"); + //return null; + } + + @Override + public Response download(String s) { + //TODO implement + throw new UnsupportedOperationException("Implement me!"); + //return null; + } + }; +// return createProxy(IFileResource.class); } public IStatisticsResource getStatisticsResource() { @@ -399,30 +440,25 @@ public URI getResourceURI(String projectSlug, String versionSlug) { } /** - * @see org.jboss.resteasy.client.core.ClientInterceptorRepositoryImpl#registerInterceptor(Object) * @param interceptor */ public void registerPrefixInterceptor(Object interceptor) { - ClientInterceptorRepository repo = getPrefixInterceptors(); - repo.registerInterceptor(interceptor); +// ClientInterceptorRepository repo = getPrefixInterceptors(); +// repo.registerInterceptor(interceptor); } /** * Workaround for signature incompatibility between RESTEasy 2.x and 3.x * @return */ - private ClientInterceptorRepository getPrefixInterceptors() { - try { - Method m = crf.getClass().getMethod("getPrefixInterceptors"); - return (ClientInterceptorRepository) m.invoke(crf); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - protected IVersionResource createIVersionResource() { - return createProxy(IVersionResource.class, getBaseUri()); - } +// private ClientInterceptorRepository getPrefixInterceptors() { +// try { +// Method m = crf.getClass().getMethod("getPrefixInterceptors"); +// return (ClientInterceptorRepository) m.invoke(crf); +// } catch (Exception e) { +// throw new RuntimeException(e); +// } +// } /** * Compares a given version identifier with the server version. diff --git a/zanata-rest-client/src/test/java/org/zanata/rest/client/ApiKeyHeaderDecoratorTest.java b/zanata-rest-client/src/test/java/org/zanata/rest/client/ApiKeyHeaderDecoratorTest.java index 49248b3f..c2d146e2 100644 --- a/zanata-rest-client/src/test/java/org/zanata/rest/client/ApiKeyHeaderDecoratorTest.java +++ b/zanata-rest-client/src/test/java/org/zanata/rest/client/ApiKeyHeaderDecoratorTest.java @@ -23,9 +23,6 @@ import javax.ws.rs.core.MultivaluedMap; -import org.jboss.resteasy.client.ClientRequest; -import org.jboss.resteasy.client.ClientResponse; -import org.jboss.resteasy.spi.interception.ClientExecutionContext; import org.junit.Test; import org.zanata.rest.RestConstant; @@ -39,31 +36,31 @@ public class ApiKeyHeaderDecoratorTest { @Test public void testHeaders() throws Exception { - String username = "username"; - String apiKey = "apiKey"; - String ver = "ver"; - ApiKeyHeaderDecorator decorator = - new ApiKeyHeaderDecorator(username, apiKey, ver); - - final ClientRequest mockRequest = - new ClientRequest("http://uri.example.com/"); - ClientExecutionContext mockCtx = new ClientExecutionContext() { - - @SuppressWarnings("rawtypes") - @Override - public ClientResponse proceed() throws Exception { - return null; - } - - @Override - public ClientRequest getRequest() { - return mockRequest; - } - }; - decorator.execute(mockCtx); - MultivaluedMap headers = mockRequest.getHeaders(); - assertEquals(username, headers.getFirst(RestConstant.HEADER_USERNAME)); - assertEquals(apiKey, headers.getFirst(RestConstant.HEADER_API_KEY)); - assertEquals(ver, headers.getFirst(RestConstant.HEADER_VERSION_NO)); +// String username = "username"; +// String apiKey = "apiKey"; +// String ver = "ver"; +// ApiKeyHeaderDecorator decorator = +// new ApiKeyHeaderDecorator(username, apiKey, ver); +// +// final ClientRequest mockRequest = +// new ClientRequest("http://uri.example.com/"); +// ClientExecutionContext mockCtx = new ClientExecutionContext() { +// +// @SuppressWarnings("rawtypes") +// @Override +// public ClientResponse proceed() throws Exception { +// return null; +// } +// +// @Override +// public ClientRequest getRequest() { +// return mockRequest; +// } +// }; +// decorator.execute(mockCtx); +// MultivaluedMap headers = mockRequest.getHeaders(); +// assertEquals(username, headers.getFirst(RestConstant.HEADER_USERNAME)); +// assertEquals(apiKey, headers.getFirst(RestConstant.HEADER_API_KEY)); +// assertEquals(ver, headers.getFirst(RestConstant.HEADER_VERSION_NO)); } }