diff --git a/pom.xml b/pom.xml index 7cb767cc..b9806882 100644 --- a/pom.xml +++ b/pom.xml @@ -38,8 +38,7 @@ 4.0.0-SNAPSHOT 4.0.0-SNAPSHOT 1.6.2 - 3.0.12.Final - 1.17.1 + 3.0.13.Final @@ -80,22 +79,6 @@ commons-logging commons-logging - - org.jboss.resteasy - resteasy-jaxrs - - - org.jboss.resteasy - resteasy-jaxb-provider - - - org.jboss.resteasy - jaxrs-api - - - org.jboss.resteasy - resteasy-multipart-provider - @@ -147,11 +130,6 @@ 2.32 - - org.jboss.resteasy - jaxrs-api - ${resteasy.version} - org.jboss.resteasy @@ -200,6 +178,45 @@ + + org.jboss.resteasy + resteasy-multipart-provider + ${resteasy.version} + + + javax.servlet + servlet-api + + + commons-logging + commons-logging + + + net.jcip + jcip-annotations + + + org.jboss.logging + jboss-logging + + + + + org.jboss.resteasy + resteasy-jaxb-provider + ${resteasy.version} + + + com.sun.xml.bind + jaxb-impl + + + + + org.jboss.resteasy + resteasy-jackson-provider + ${resteasy.version} + org.apache.commons commons-lang3 diff --git a/stub-server/pom.xml b/stub-server/pom.xml index 5a03e2f3..f79e6468 100644 --- a/stub-server/pom.xml +++ b/stub-server/pom.xml @@ -23,18 +23,13 @@ - org.jboss.resteasy - jaxrs-api + org.jboss.spec.javax.ws.rs + jboss-jaxrs-api_2.0_spec org.zanata zanata-common-api - - - com.sun.jersey - jersey-core - org.jboss.spec.javax.ws.rs jboss-jaxrs-api_2.0_spec @@ -83,26 +78,10 @@ org.jboss.resteasy resteasy-jaxb-provider - - - com.sun.xml.bind - jaxb-impl - - org.jboss.resteasy resteasy-multipart-provider - - - javax.servlet - servlet-api - - - commons-logging - commons-logging - - org.scannotation diff --git a/zanata-cli/src/test/java/org/zanata/client/ClientToServerTest.java b/zanata-cli/src/test/java/org/zanata/client/ClientToServerTest.java index 3b420f3a..3136c8fc 100644 --- a/zanata-cli/src/test/java/org/zanata/client/ClientToServerTest.java +++ b/zanata-cli/src/test/java/org/zanata/client/ClientToServerTest.java @@ -75,7 +75,7 @@ public void test503ResponseHandling() throws IOException { Mockito.verify(mockAbortStrategy).abort(throwableCapture.capture()); assertThat("Client will display meaningful message for 503", throwableCapture.getValue().getMessage() - .contains("503 Service Unavailable")); + .contains("unavailable")); } } } diff --git a/zanata-client-commands/pom.xml b/zanata-client-commands/pom.xml index 8f30765c..6445d1b0 100644 --- a/zanata-client-commands/pom.xml +++ b/zanata-client-commands/pom.xml @@ -21,20 +21,10 @@ org.zanata zanata-common-api - - - com.sun.jersey - jersey-client - - - com.sun.jersey - jersey-core - - - org.jboss.spec.javax.ws.rs - jboss-jaxrs-api_2.0_spec - - + + + org.jboss.spec.javax.ws.rs + jboss-jaxrs-api_2.0_spec org.zanata @@ -55,28 +45,12 @@ org.zanata zanata-rest-client - - - com.sun.jersey - jersey-client - - - com.sun.jersey - jersey-core - - org.zanata zanata-adapter-glossary - - com.sun.jersey - jersey-client - ${jersey.version} - - com.google.code.findbugs annotations @@ -94,11 +68,6 @@ slf4j-api - - com.sun.jersey - jersey-core - ${jersey.version} - junit junit diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/UpdateChecker.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/UpdateChecker.java index 509b7ad8..93400d9f 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/UpdateChecker.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/UpdateChecker.java @@ -20,10 +20,6 @@ */ package org.zanata.client.commands; -import static org.zanata.client.commands.ConsoleInteractorImpl.AnswerValidator; -import static org.zanata.client.commands.Messages.get; -import static org.zanata.util.VersionUtility.getVersionInfo; - import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; @@ -31,9 +27,14 @@ import java.io.InputStreamReader; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.apache.commons.io.output.FileWriterWithEncoding; import org.fedorahosted.openprops.Properties; +import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.joda.time.DateTime; import org.joda.time.Days; import org.joda.time.Weeks; @@ -41,16 +42,15 @@ import org.joda.time.format.DateTimeFormatter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; -import com.sun.jersey.api.client.Client; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.WebResource; -import com.sun.jersey.api.client.config.DefaultClientConfig; + +import static org.zanata.client.commands.ConsoleInteractorImpl.AnswerValidator; +import static org.zanata.client.commands.Messages.get; +import static org.zanata.util.VersionUtility.getVersionInfo; /** * This class checks whether there is newer version of client available. It will @@ -200,23 +200,19 @@ public void checkNewerVersion() { * @return latest version of client in sonatype oss */ private Optional checkLatestVersion(ConsoleInteractor console) { - ClientResponse response; + Response response; try { - DefaultClientConfig clientConfig = - new DefaultClientConfig(); - - Client client = com.sun.jersey.api.client.Client.create( - clientConfig); - WebResource target = - client.resource(sonatypeRestUrl) + Client client = ResteasyClientBuilder.newClient(); + WebTarget target = + client.target(sonatypeRestUrl) .path("artifact/maven/resolve") .queryParam("g", "org.zanata") .queryParam("a", "client") .queryParam("p", "pom") .queryParam("v", "LATEST") .queryParam("r", "releases"); - response = target.get(ClientResponse.class); - if (response.getClientResponseStatus() != ClientResponse.Status.OK) { + response = target.request(MediaType.APPLICATION_XML_TYPE).get(); + if (response.getStatusInfo() != Response.Status.OK) { log.debug( "Failed to resolve latest client artifact [status {}]. Ignored", response.getStatus()); @@ -230,14 +226,14 @@ private Optional checkLatestVersion(ConsoleInteractor console) { } // cheap xml parsing String payload = - response.getEntity(String.class).replaceAll("\\n", ""); + response.readEntity(String.class).replaceAll("\\n", ""); Pattern pattern = Pattern.compile("^.+(.+).+"); Matcher matcher = pattern.matcher(payload); - return matcher.matches() ? Optional.of(matcher.group(1)) : Optional - . absent(); + return matcher.matches() ? Optional.of(matcher.group(1)) : + Optional.absent(); } - private static enum Frequency { + private enum Frequency { weekly, monthly, daily; static Frequency from(String value) { try { diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/pull/GlossaryPullCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/pull/GlossaryPullCommand.java index 4483734a..4e0fd6ff 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/pull/GlossaryPullCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/glossary/pull/GlossaryPullCommand.java @@ -25,6 +25,9 @@ import java.io.InputStream; import java.io.OutputStream; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.core.Response; + import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,7 +40,6 @@ import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; -import com.sun.jersey.api.client.ClientResponse; /** * @@ -88,23 +90,22 @@ public void run() throws Exception { : client.getProjectQualifiedName(project); log.info("Pulling glossary from server"); - ClientResponse response = - client.downloadFile(fileType, transLang, qualifiedName); - - if (response - .getClientResponseStatus() == ClientResponse.Status.NOT_FOUND) { + Response response; + try { + response = + client.downloadFile(fileType, transLang, qualifiedName); + } catch (NotFoundException e) { log.info("No glossary file in server"); return; } - ClientUtil.checkResult(response); - InputStream glossaryFile = response.getEntity(InputStream.class); + InputStream glossaryFile = response.readEntity(InputStream.class); if (glossaryFile == null) { log.info("No glossary file in server"); return; } String fileName = - ClientUtil.getFileNameFromHeader(response.getHeaders()); + ClientUtil.getFileNameFromHeader(response.getStringHeaders()); File file = new File(fileName); PathUtil.makeDirs(file.getParentFile()); try (OutputStream out = new FileOutputStream(file)) { 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 12eb509f..e35bdb96 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 @@ -41,7 +41,6 @@ import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import com.sun.jersey.api.client.UniformInterfaceException; /** * @author Patrick Huang = 399) { - InitCommand.offerRetryOnServerError(e, consoleInteractor); - createNewProject(); - } + } catch (ClientErrorException | ServerErrorException e) { + InitCommand.offerRetryOnServerError(e, consoleInteractor); + createNewProject(); } consoleInteractor.printfln(Confirmation, get("project.created")); opts.setProj(projectId); diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/pull/PullCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/pull/PullCommand.java index 379c32de..a38ff625 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/pull/PullCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/pull/PullCommand.java @@ -10,7 +10,9 @@ import java.util.SortedSet; import java.util.TreeSet; +import javax.ws.rs.NotFoundException; import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -24,7 +26,6 @@ import org.zanata.common.LocaleId; import org.zanata.common.io.FileDetails; import org.zanata.rest.RestUtil; -import org.zanata.rest.client.ClientUtil; import org.zanata.rest.client.RestClientFactory; import org.zanata.rest.dto.resource.Resource; import org.zanata.rest.dto.resource.TranslationsResource; @@ -33,7 +34,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.collect.Lists; -import com.sun.jersey.api.client.ClientResponse; /** * @author Sean Flanigan fileTypeInfoList(FileResourceClient client) { try { return client.fileTypeInfoList(); - } catch (UniformInterfaceException e) { - if (e.getResponse().getStatus() == 404) { - log.info("Detected old Zanata Server; using hard-coded file types."); - // probably running against an old Zanata Server - return fileTypeInfoListWorkaround(); - } else { - throw e; - } + } catch (NotFoundException e) { + log.info("Detected old Zanata Server; using hard-coded file types."); + // probably running against an old Zanata Server + return fileTypeInfoListWorkaround(); } } diff --git a/zanata-client-commands/src/test/java/org/zanata/client/MockServerRule.java b/zanata-client-commands/src/test/java/org/zanata/client/MockServerRule.java index dcaeb58a..e37cd809 100644 --- a/zanata-client-commands/src/test/java/org/zanata/client/MockServerRule.java +++ b/zanata-client-commands/src/test/java/org/zanata/client/MockServerRule.java @@ -37,6 +37,9 @@ import java.util.Set; import java.util.stream.Collectors; +import javax.ws.rs.core.Response; + +import org.jboss.resteasy.specimpl.MultivaluedMapImpl; import org.junit.rules.ExternalResource; import org.mockito.ArgumentCaptor; import org.mockito.Captor; @@ -68,8 +71,6 @@ import org.zanata.rest.service.FileResource; import com.google.common.base.Throwables; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.core.util.MultivaluedMapImpl; /** * Test rule to set up push and/or pull commands which will interact with @@ -97,13 +98,13 @@ public class MockServerRule extends ExternalResource { @Captor private ArgumentCaptor transResourceCaptor; @Mock - private ClientResponse transResourceResponse; + private Response transResourceResponse; @Captor private ArgumentCaptor uploadFormCaptor; @Mock - private ClientResponse downloadSourceResponse; + private Response downloadSourceResponse; @Mock - private ClientResponse downloadTransResponse; + private Response downloadTransResponse; @Mock private RestClientFactory clientFactory; @Mock @@ -271,9 +272,9 @@ public PullCommand createPullCommand(List remoteDocList, eq(getPullOpts().getCreateSkeletons()), anyString())) .thenReturn(transResourceResponse); when(transResourceResponse.getStatus()).thenReturn(200); - when(transResourceResponse.getHeaders()).thenReturn( + when(transResourceResponse.getStringHeaders()).thenReturn( new MultivaluedMapImpl()); - when(transResourceResponse.getEntity(TranslationsResource.class)) + when(transResourceResponse.readEntity(TranslationsResource.class)) .thenReturn(transResourceOnServer); return new PullCommand(pullOpts, clientFactory); } @@ -354,10 +355,10 @@ public RawPullCommand createRawPullCommand( eq(pullOpts.getProj()), eq(pullOpts.getProjectVersion()), eq(FileResource.FILETYPE_RAW_SOURCE_DOCUMENT), anyString())).thenReturn(downloadSourceResponse); - when(downloadSourceResponse.getClientResponseStatus()).thenReturn( - ClientResponse.Status.OK); + when(downloadSourceResponse.getStatusInfo()).thenReturn( + Response.Status.OK); when(downloadSourceResponse.getStatus()).thenReturn(200); - when(downloadSourceResponse.getEntity(InputStream.class)) + when(downloadSourceResponse.readEntity(InputStream.class)) .thenReturn(sourceFileStream); // return provide translation stream when(fileResourceClient.downloadTranslationFile(eq(pullOpts.getProj()), @@ -365,9 +366,9 @@ public RawPullCommand createRawPullCommand( anyString())).thenReturn(downloadTransResponse); when(downloadTransResponse.getStatus()).thenReturn(200); when(downloadTransResponse.getHeaders()).thenReturn(new MultivaluedMapImpl()); - when(downloadTransResponse.getClientResponseStatus()).thenReturn( - ClientResponse.Status.OK); - when(downloadTransResponse.getEntity(InputStream.class)) + when(downloadTransResponse.getStatusInfo()).thenReturn( + Response.Status.OK); + when(downloadTransResponse.readEntity(InputStream.class)) .thenReturn(transFileStream); return new RawPullCommand(pullOpts, fileResourceClient, clientFactory); } diff --git a/zanata-rest-client/pom.xml b/zanata-rest-client/pom.xml index 96d62056..5fc8eb01 100644 --- a/zanata-rest-client/pom.xml +++ b/zanata-rest-client/pom.xml @@ -20,24 +20,10 @@ - - - org.jboss.resteasy - jaxrs-api - test - org.zanata zanata-common-api - - com.sun.jersey - jersey-client - - - com.sun.jersey - jersey-core - org.jboss.spec.javax.ws.rs jboss-jaxrs-api_2.0_spec @@ -57,20 +43,23 @@ - com.sun.jersey - jersey-core - ${jersey.version} + org.jboss.resteasy + resteasy-client + ${resteasy.version} - com.sun.jersey - jersey-client - ${jersey.version} + org.jboss.resteasy + resteasy-multipart-provider - com.sun.jersey.contribs - jersey-multipart - ${jersey.version} + org.jboss.resteasy + resteasy-jackson-provider + + org.jboss.resteasy + resteasy-jaxb-provider + + org.codehaus.jackson diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/AcceptTypeFilter.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/AcceptTypeFilter.java deleted file mode 100644 index 6e1c7119..00000000 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/AcceptTypeFilter.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 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; - -/** - * This adds a generic Accept header to all request. It is a workaround for - * RESTEasy 2 service. Clients requiring specific Accpet type can override it. - * - * @author Patrick Huang pahuang@redhat.com - */ -public class AcceptTypeFilter extends ClientFilter { - @Override - public ClientResponse handle(ClientRequest cr) - throws ClientHandlerException { - MultivaluedMap headers = cr.getHeaders(); - // make sure we have at least one Accept header otherwise jersey will - // insert an "Accept: text/html, image/gif, image/jpeg, *" which breaks - // RESTEasy 2 - headers.add("Accept", "application/*"); - return getNext().handle(cr); - } -} diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/AccountClient.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/AccountClient.java index 940892aa..2c15f8ee 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/AccountClient.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/AccountClient.java @@ -23,11 +23,13 @@ import java.net.URI; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.MediaType; + import org.zanata.rest.MediaTypes; import org.zanata.rest.dto.Account; -import com.sun.jersey.api.client.WebResource; - /** * @author Patrick Huang pahuang@redhat.com @@ -47,14 +49,14 @@ public Account get(String username) { } public void put(String username, Account account) { - webResource(username).type( - MediaTypes.APPLICATION_ZANATA_ACCOUNT_XML) - .put(account); + webResource(username) + .put(Entity.entity(account, MediaTypes.APPLICATION_ZANATA_ACCOUNT_XML)); } - private WebResource webResource(String username) { - return factory.getClient().resource(baseUri) + private Invocation.Builder webResource(String username) { + return factory.getClient().target(baseUri) .path("accounts").path("u") - .path(username); + .path(username) + .request(MediaTypes.APPLICATION_ZANATA_ACCOUNT_XML); } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderFilter.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderFilter.java index 77c67af4..357c1879 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderFilter.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/ApiKeyHeaderFilter.java @@ -21,19 +21,16 @@ package org.zanata.rest.client; +import java.io.IOException; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientRequestFilter; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.Provider; import org.zanata.rest.RestConstant; -import com.google.common.annotations.VisibleForTesting; -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 { +public class ApiKeyHeaderFilter implements ClientRequestFilter { private String apiKey; private String username; private String ver; @@ -44,21 +41,6 @@ public ApiKeyHeaderFilter(String username, String apiKey, String ver) { 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 handleNext(cr); - } - - @VisibleForTesting - protected ClientResponse handleNext(ClientRequest cr) { - return getNext().handle(cr); - } - public String getUsername() { return username; } @@ -66,5 +48,13 @@ public String getUsername() { public void setUsername(String username) { this.username = username; } + + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + MultivaluedMap headers = requestContext.getHeaders(); + headers.add(RestConstant.HEADER_USERNAME, username); + headers.add(RestConstant.HEADER_API_KEY, apiKey); + headers.add(RestConstant.HEADER_VERSION_NO, ver); + } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/AsyncProcessClient.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/AsyncProcessClient.java index d7c19bcf..ba39f699 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/AsyncProcessClient.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/AsyncProcessClient.java @@ -23,15 +23,19 @@ import java.net.URI; import java.util.Set; + import javax.ws.rs.DefaultValue; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.zanata.common.LocaleId; import org.zanata.rest.dto.ProcessStatus; import org.zanata.rest.dto.resource.Resource; import org.zanata.rest.dto.resource.TranslationsResource; import org.zanata.rest.service.AsynchronousProcessResource; -import com.sun.jersey.api.client.Client; -import com.sun.jersey.api.client.WebResource; /** * @author Patrick Huang extensions, @DefaultValue("true") boolean copytrans) { Client client = factory.getClient(); - CacheResponseFilter filter = new CacheResponseFilter(); - client.addFilter(filter); - WebResource webResource = client.resource(baseUri) + WebTarget webResource = client.target(baseUri) .path(AsynchronousProcessResource.SERVICE_PATH) .path("projects").path("p").path(projectSlug) .path("iterations").path("i").path(iterationSlug) .path("r").path(idNoSlash); - webResource - .queryParams(ClientUtil.asMultivaluedMap("ext", extensions)) + Response response = webResource + .queryParam("ext", extensions.toArray()) .queryParam("copyTrans", String.valueOf(copytrans)) - .put(resource); - client.removeFilter(filter); - return filter.getEntity(ProcessStatus.class); + .request(MediaType.APPLICATION_XML_TYPE) + .put(Entity.xml(resource)); + response.bufferEntity(); + return response.readEntity(ProcessStatus.class); } @Override @@ -80,27 +83,29 @@ public ProcessStatus startTranslatedDocCreationOrUpdate(String idNoSlash, TranslationsResource translatedDoc, Set extensions, String merge, @DefaultValue("false") boolean myTrans) { Client client = factory.getClient(); - CacheResponseFilter filter = new CacheResponseFilter(); - client.addFilter(filter); - WebResource webResource = client.resource(baseUri) + WebTarget webResource = client.target(baseUri) .path(AsynchronousProcessResource.SERVICE_PATH) .path("projects").path("p").path(projectSlug) .path("iterations").path("i").path(iterationSlug) .path("r").path(idNoSlash) .path("translations").path(locale.toString()); - webResource - .queryParams(ClientUtil.asMultivaluedMap("ext", extensions)) + Response response = webResource + .queryParam("ext", extensions.toArray()) .queryParam("merge", merge) .queryParam("assignCreditToUploader", String.valueOf(myTrans)) - .put(translatedDoc); - client.removeFilter(filter); - return filter.getEntity(ProcessStatus.class); + .request(MediaType.APPLICATION_XML_TYPE) + .put(Entity + .xml(translatedDoc)); + response.bufferEntity(); + return response.readEntity(ProcessStatus.class); } @Override public ProcessStatus getProcessStatus(String processId) { - return factory.getClient().resource(baseUri) + return factory.getClient().target(baseUri) .path(AsynchronousProcessResource.SERVICE_PATH) - .path(processId).get(ProcessStatus.class); + .path(processId) + .request(MediaType.APPLICATION_XML_TYPE) + .get(ProcessStatus.class); } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/CacheResponseFilter.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/CacheResponseFilter.java deleted file mode 100644 index eb92abfd..00000000 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/CacheResponseFilter.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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 - */ -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/zanata-rest-client/src/main/java/org/zanata/rest/client/ClientUtil.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/ClientUtil.java index df13acc7..a73f2287 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/ClientUtil.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/ClientUtil.java @@ -27,80 +27,17 @@ import java.net.URL; import java.util.regex.Matcher; import java.util.regex.Pattern; - import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; -import com.google.common.base.Strings; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.core.util.MultivaluedMapImpl; import org.apache.commons.lang3.StringUtils; + /** * @author Patrick Huang pahuang@redhat.com */ public class ClientUtil { - static MultivaluedMap asMultivaluedMap( - String paramKey, Iterable values) { - MultivaluedMapImpl map = new MultivaluedMapImpl(); - if (values == null) { - return map; - } - for (String extension : values) { - map.add(paramKey, extension); - } - return map; - } - - public static void checkResult(ClientResponse response) { - ClientResponse.Status responseStatus = - response.getClientResponseStatus(); - int statusCode = response.getStatus(); - - if (responseStatus == ClientResponse.Status.UNAUTHORIZED) { - throw new RuntimeException("Incorrect username/password"); - } else if (responseStatus == ClientResponse.Status.SERVICE_UNAVAILABLE) { - throw new RuntimeException("Service is currently unavailable. " + - "Please check outage notification or try again later."); - } else if (responseStatus == ClientResponse.Status.MOVED_PERMANENTLY - || statusCode == 302) { - // if server returns a redirect (most likely due to http to https - // redirect), we don't want to bury this information in a xml - // marshalling exception. - String movedTo = response.getHeaders().getFirst("Location"); - - String message; - if (!Strings.isNullOrEmpty(movedTo)) { - String baseUrl = getBaseURL(movedTo); - message = "Server returned a redirect to:" + baseUrl + - ". You must change your url option or config file."; - } else { - message = - "Server returned a redirect. You must change your url option or config file."; - } - throw new RuntimeException(message); - } else if (statusCode >= 399) { - String annotString = ""; - String uriString = ""; - String entity = ""; - try { - entity = ": " + response.getEntity(String.class); - } finally { - // ignore - } - String msg = - "operation returned " - + statusCode - + " (" - + Response.Status.fromStatusCode(statusCode) + ")" - + entity + uriString - + annotString; - throw new RuntimeException(msg); - } - } - public static String getBaseURL(String movedTo) { try { URL url = new URI(movedTo).toURL(); @@ -131,4 +68,5 @@ public static String getFileNameFromHeader(MultivaluedMap header Matcher m = p.matcher(contentDisposition); return m.find() ? m.group(1) : null; } + } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/CopyTransClient.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/CopyTransClient.java index c356d179..c52a2a7c 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/CopyTransClient.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/CopyTransClient.java @@ -23,10 +23,14 @@ import java.net.URI; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + import org.zanata.rest.dto.CopyTransStatus; import org.zanata.rest.service.CopyTransResource; -import com.sun.jersey.api.client.Client; -import com.sun.jersey.api.client.WebResource; /** * @author Patrick Huang acceptedFileTypes() { List types = factory.getClient() - .resource(baseUri) + .target(baseUri) .path(FileResource.SERVICE_PATH + FileResource.ACCEPTED_TYPE_LIST_RESOURCE) + .request(MediaType.APPLICATION_JSON_TYPE) .get(new GenericType>() { }); return types; @@ -69,9 +72,10 @@ public List acceptedFileTypes() { public List fileTypeInfoList() { List types = factory.getClient() - .resource(baseUri) + .target(baseUri) .path(FileResource.SERVICE_PATH + FileResource.FILE_TYPE_INFO_RESOURCE) + .request(MediaType.APPLICATION_JSON_TYPE) .get(new GenericType>() { }); return types; @@ -81,53 +85,33 @@ 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) + Invocation.Builder builder = client + .target(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; - } + .request(MediaType.APPLICATION_XML_TYPE); - 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; + // there seems to be a gap in the resteasy api to support multipart form + // with this fluent client. We have to provide the @MultipartForm + // annotation to the method. + // otherwise Resteasy can't find the writer for multipart form + Response response = builder.post(Entity.entity(documentFileUploadForm, + MediaType.MULTIPART_FORM_DATA_TYPE, multipartFormAnnotations)); + response.bufferEntity(); + + return response.readEntity(ChunkUploadResponse.class); } + 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) + Invocation.Builder builder = client.target(baseUri) .path(FileResource.SERVICE_PATH) .path("translation") .path(projectSlug) @@ -135,41 +119,42 @@ public ChunkUploadResponse uploadTranslationFile( .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; + .request(MediaType.APPLICATION_XML_TYPE); + + + Response response = builder.post(Entity.entity(documentFileUploadForm, + MediaType.MULTIPART_FORM_DATA_TYPE, multipartFormAnnotations)); + response.bufferEntity(); + return response.readEntity(ChunkUploadResponse.class); } - public ClientResponse downloadSourceFile(String projectSlug, + public Response downloadSourceFile(String projectSlug, String iterationSlug, String fileType, String docId) { - WebResource webResource = factory.getClient().resource(baseUri) + WebTarget webResource = factory.getClient().target(baseUri) .path(FileResource.SERVICE_PATH).path("source") .path(projectSlug).path(iterationSlug).path(fileType); - return webResource.queryParam("docId", docId).get(ClientResponse.class); + return webResource.queryParam("docId", docId) + .request(MediaType.APPLICATION_OCTET_STREAM_TYPE) + .get(); } - public ClientResponse downloadTranslationFile(String projectSlug, + public Response downloadTranslationFile(String projectSlug, String iterationSlug, String locale, String fileExtension, String docId) { - WebResource webResource = factory.getClient().resource(baseUri) + WebTarget webResource = factory.getClient().target(baseUri) .path(FileResource.SERVICE_PATH).path("translation") .path(projectSlug).path(iterationSlug).path(locale) .path(fileExtension); - return webResource.queryParam("docId", docId).get(ClientResponse.class); + return webResource.queryParam("docId", docId) + .request(MediaType.APPLICATION_OCTET_STREAM_TYPE).get(); } - private static FormDataMultiPart addBodyPartIfPresent( - FormDataMultiPart form, String field, T value) { - if (value != null) { - return form.field(field, value.toString()); + private static class MultipartFormLiteral implements MultipartForm { + + @Override + public java.lang.Class annotationType() { + return MultipartForm.class; } - return form; } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/GlossaryClient.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/GlossaryClient.java index 48d83d6e..e56be907 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/GlossaryClient.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/GlossaryClient.java @@ -21,25 +21,21 @@ package org.zanata.rest.client; -import java.lang.reflect.Type; import java.net.URI; import java.util.List; - +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.GenericEntity; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.zanata.common.LocaleId; import org.zanata.rest.dto.GlossaryEntry; -import org.zanata.rest.dto.Project; import org.zanata.rest.dto.QualifiedName; import org.zanata.rest.service.GlossaryResource; -import org.zanata.rest.service.ProjectResource; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.GenericType; -import com.sun.jersey.api.client.WebResource; /** * @author Patrick Huang glossaryEntries, LocaleId localeId, String qualifiedName) { - Type genericType = new GenericType>() { - }.getType(); - Object entity = - new GenericEntity>(glossaryEntries, - genericType); + Entity> entity = Entity.json(glossaryEntries); webResource().path("entries").queryParam("locale", localeId.getId()) .queryParam("qualifiedName", qualifiedName) - .type(MediaType.APPLICATION_XML_TYPE).post(entity); + .request(MediaType.APPLICATION_JSON_TYPE).post(entity); } - public ClientResponse downloadFile(String fileType, + public Response downloadFile(String fileType, ImmutableList transLang, String qualifiedName) { if (transLang != null && !transLang.isEmpty()) { return webResource().path("file").queryParam("fileType", fileType) .queryParam("locales", Joiner.on(",").join(transLang)) .queryParam("qualifiedName", qualifiedName) - .get(ClientResponse.class); + .request(MediaType.APPLICATION_OCTET_STREAM_TYPE) + .get(); } return webResource().path("file").queryParam("fileType", fileType) .queryParam("qualifiedName", qualifiedName) - .get(ClientResponse.class); + .request(MediaType.APPLICATION_OCTET_STREAM_TYPE) + .get(); } public void delete(String id, String qualifiedName) { webResource().path("entries/" + id) - .queryParam("qualifiedName", qualifiedName).delete(); + .queryParam("qualifiedName", qualifiedName) + .request(MediaType.APPLICATION_JSON_TYPE) + .delete(); } public int deleteAll(String qualifiedName) { return webResource().queryParam("qualifiedName", qualifiedName) + .request(MediaType.APPLICATION_JSON_TYPE) .delete(Integer.class); } public String getProjectQualifiedName(String projectSlug) { return projectGlossaryWebResource(projectSlug).path("qualifiedName") + .request(MediaType.APPLICATION_JSON_TYPE) .get(QualifiedName.class).getName(); } public String getGlobalQualifiedName() { - return webResource().path("qualifiedName").get(QualifiedName.class) + return webResource().path("qualifiedName") + .request(MediaType.APPLICATION_JSON_TYPE) + .get(QualifiedName.class) .getName(); } - private WebResource webResource() { - return factory.getClient().resource(baseUri) + private WebTarget webResource() { + return factory.getClient().target(baseUri) .path(GlossaryResource.SERVICE_PATH); } - private WebResource projectGlossaryWebResource(String projectSlug) { + private WebTarget projectGlossaryWebResource(String projectSlug) { return factory.getClient() - .resource(factory.getBaseUri()) + .target(factory.getBaseUri()) .path("projects").path("p").path(projectSlug).path("glossary"); } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/InvalidContentTypeFilter.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/InvalidContentTypeFilter.java index 0889641b..b9e27e56 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/InvalidContentTypeFilter.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/InvalidContentTypeFilter.java @@ -20,28 +20,23 @@ */ package org.zanata.rest.client; -import java.util.Set; +import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientResponseContext; +import javax.ws.rs.client.ClientResponseFilter; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Predicate; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.sun.jersey.api.client.ClientHandler; -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; /** * @author Patrick Huang pahuang@redhat.com */ -public class InvalidContentTypeFilter extends ClientFilter { +public class InvalidContentTypeFilter implements ClientResponseFilter { private static final Logger log = LoggerFactory.getLogger(InvalidContentTypeFilter.class); private static final String ERROR_MSG = @@ -54,28 +49,6 @@ public class InvalidContentTypeFilter extends ClientFilter { private static final Pattern VALID_TYPES_REGEX = Pattern.compile("application/.*"); - @Override - public ClientResponse handle(ClientRequest clientRequest) - throws ClientHandlerException { - ClientHandler ch = getNext(); - ClientResponse resp = ch.handle(clientRequest); - - if (resp.getClientResponseStatus().getFamily().equals( - Response.Status.Family.SUCCESSFUL) && - !isContentTypeCompatible(resp.getType())) { - log.error(ERROR_MSG); - String title = findPageTitle(resp); - String snippet = String.format( - "Wrong content type received: [%s]. Content page title: [%s]", - resp.getType(), title); - - log.error(snippet); - throw new IllegalStateException(snippet); - } else { - return resp; - } - } - @VisibleForTesting protected static boolean isContentTypeCompatible( final MediaType responseContentType) { @@ -93,13 +66,19 @@ protected static boolean isContentTypeCompatible( return matcher.matches(); } - private String findPageTitle(ClientResponse resp) { - String body = resp.getEntity(String.class).replaceAll("\\n", " "); - Pattern pattern = Pattern.compile(".*(.*).*"); - Matcher matcher = pattern.matcher(body); - if (matcher.matches()) { - return matcher.group(1); + @Override + public void filter(ClientRequestContext requestContext, + ClientResponseContext responseContext) throws IOException { + if (responseContext.getStatusInfo().getFamily().equals( + Response.Status.Family.SUCCESSFUL) && + !isContentTypeCompatible(responseContext.getMediaType())) { + log.error(ERROR_MSG); + String snippet = String.format( + "Wrong content type received: [%s]", + responseContext.getMediaType()); + + log.error(snippet); + throw new IllegalStateException(snippet); } - return ""; } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/ProjectClient.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/ProjectClient.java index d1ae8e44..ee4f4e64 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/ProjectClient.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/ProjectClient.java @@ -21,9 +21,11 @@ package org.zanata.rest.client; -import org.zanata.rest.dto.Project; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.MediaType; -import com.sun.jersey.api.client.WebResource; +import org.zanata.rest.dto.Project; /** * @author Patrick Huang getLocales() { return restClientFactory.getClient() - .resource(restClientFactory.getBaseUri()) + .target(restClientFactory.getBaseUri()) .path("projects").path("p").path(projectSlug) .path("iterations").path("i").path(versionSlug) .path("locales") + .request(MediaType.APPLICATION_XML_TYPE) .get(new GenericType>() { }); } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/ProjectsClient.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/ProjectsClient.java index 24eca02b..47d4ebf3 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/ProjectsClient.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/ProjectsClient.java @@ -21,9 +21,11 @@ package org.zanata.rest.client; +import javax.ws.rs.core.GenericType; +import javax.ws.rs.core.MediaType; + import org.zanata.rest.dto.Project; import org.zanata.rest.service.ProjectsResource; -import com.sun.jersey.api.client.GenericType; /** * @author Patrick Huang () { }); } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/RedirectFilter.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/RedirectFilter.java index 8bd5c8e1..a133ac87 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/RedirectFilter.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/RedirectFilter.java @@ -20,50 +20,37 @@ */ package org.zanata.rest.client; +import java.io.IOException; import java.net.URI; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientResponseContext; +import javax.ws.rs.client.ClientResponseFilter; import javax.ws.rs.core.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.sun.jersey.api.client.ClientHandler; -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; /** + * Resteasy does not support following redirect. https://issues.jboss.org/browse/RESTEASY-1075 + *

+ * However there is a workaround. https://github.com/teacurran/sonar-bitbucket/commit/fa978b3d7c0c98ee0bc60c908379fc42dbeae5f4 + * * @author Patrick Huang pahuang@redhat.com */ -public class RedirectFilter extends ClientFilter { +public class RedirectFilter implements ClientResponseFilter { private static final Logger log = LoggerFactory.getLogger(RedirectFilter.class); @Override - public ClientResponse handle(ClientRequest clientRequest) - throws ClientHandlerException { - ClientHandler ch = getNext(); - ClientResponse resp = ch.handle(clientRequest); - - if (resp.getClientResponseStatus().getFamily() != + public void filter(ClientRequestContext requestContext, + ClientResponseContext responseContext) throws IOException { + if (responseContext.getStatusInfo().getFamily() == Response.Status.Family.REDIRECTION) { - return resp; - } else { - // try location only if for GET and HEAD - String method = clientRequest.getMethod(); - if ("HEAD".equals(method) || "GET".equals(method)) { - log.debug( - "Server returns redirection status: {}. Try to follow it", - resp.getClientResponseStatus()); - URI redirectTarget = resp.getLocation(); - if (redirectTarget != null) { - clientRequest.setURI(redirectTarget); - } - return ch.handle(clientRequest); - } else { - throw new IllegalStateException( - "Received status " + resp.getClientResponseStatus() + - ". Check your server URL (e.g. used http instead of https)"); - } + URI redirectTarget = responseContext.getLocation(); + throw new IllegalStateException( + String.format( + "Received status %s. Redirected to %s. Check your server URL (e.g. used http instead of https)", + responseContext.getStatusInfo(), redirectTarget)); } } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/ResponseStatusFilter.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/ResponseStatusFilter.java new file mode 100644 index 00000000..1b187949 --- /dev/null +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/ResponseStatusFilter.java @@ -0,0 +1,122 @@ +/* + * Copyright 2016, 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.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import javax.ws.rs.ClientErrorException; +import javax.ws.rs.NotAuthorizedException; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.RedirectionException; +import javax.ws.rs.ServerErrorException; +import javax.ws.rs.ServiceUnavailableException; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientResponseContext; +import javax.ws.rs.client.ClientResponseFilter; +import javax.ws.rs.core.Response; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.common.base.Strings; + +/** + * @author Patrick Huang pahuang@redhat.com + */ +public class ResponseStatusFilter implements ClientResponseFilter { + private static final Logger log = + LoggerFactory.getLogger(ResponseStatusFilter.class); + @Override + public void filter(ClientRequestContext requestContext, + ClientResponseContext responseContext) throws IOException { + int statusCode = responseContext.getStatus(); + Response.StatusType responseStatus = responseContext.getStatusInfo(); + + if (isRedirect(responseStatus)) { + // if server returns a redirect (most likely due to http to https + // redirect), we don't want to bury this information in a xml + // marshalling exception. + String message = + "Server returned a redirect. You must change your url option or config file."; + // getLocation() can return null but it's acceptable + throw new RedirectionException(message, statusCode, + responseContext.getLocation()); + } else if (statusCode >= 399) { + URI uri = requestContext.getUri(); + String entity = tryGetEntity(responseContext); + String msg = + generateErrorMessage(statusCode, responseStatus, uri, + entity); + + if (responseStatus == Response.Status.UNAUTHORIZED) { + throw new NotAuthorizedException("Incorrect username/password"); + } else if (responseStatus == Response.Status.NOT_FOUND) { + throw new NotFoundException(msg); + } else if (statusCode < 500) { + throw new ClientErrorException(msg, statusCode); + } else if (responseStatus == Response.Status.SERVICE_UNAVAILABLE) { + throw new ServiceUnavailableException( + "Service is currently unavailable. " + + "Please check outage notification or try again later."); + } else { + if (responseStatus == Response.Status.SERVICE_UNAVAILABLE) { + msg = "Service is currently unavailable. " + + "Please check outage notification or try again later."; + throw new ServiceUnavailableException(msg); + } + throw new ServerErrorException(msg, statusCode); + } + } + } + + private static boolean isRedirect(Response.StatusType statusCode) { + return statusCode == Response.Status.MOVED_PERMANENTLY + || statusCode == Response.Status.FOUND; + } + + private static String tryGetEntity(ClientResponseContext responseContext) { + String entity = ""; + if (responseContext.hasEntity()) { + try (BufferedInputStream bufferedIs = new BufferedInputStream( + responseContext.getEntityStream()); + ByteArrayOutputStream result = new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int length; + while ((length = bufferedIs.read(buffer)) != -1) { + result.write(buffer, 0, length); + } + entity = ":" + result.toString("UTF-8"); + + } catch (Exception e) { + log.debug("error reading input stream", e); + } + } + return entity; + } + + private static String generateErrorMessage(int statusCode, + Response.StatusType responseStatus, URI uri, String entity) { + return String.format("operation to [%s] returned %d (%s):%s", + uri, statusCode, responseStatus, entity); + } +} diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/RestClientFactory.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/RestClientFactory.java index b1f543ee..38b581aa 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/RestClientFactory.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/RestClientFactory.java @@ -29,26 +29,22 @@ 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 javax.ws.rs.client.Client; +import javax.ws.rs.core.MediaType; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; -import org.codehaus.jackson.jaxrs.JacksonJsonProvider; +import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.zanata.rest.MediaTypes; import org.zanata.rest.RestConstant; 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 getResourceMeta(Set extensions) { Client client = factory.getClient(); - WebResource webResource = getBaseServiceResource(client) - .queryParams(ClientUtil.asMultivaluedMap( - "ext", extensions)); - return webResource - .get(new GenericType>() { - }); + WebTarget webResource = getBaseServiceResource(client); + if (extensions != null) { + webResource.queryParam("ext", extensions.toArray()); + } + return webResource.request(MediaType.APPLICATION_XML_TYPE) + .get(new GenericType>() {}); } - private WebResource getBaseServiceResource(Client client) { - return client.resource(baseUri) + private WebTarget getBaseServiceResource(Client client) { + return client.target(baseUri) .path("projects").path("p") .path(project) .path("iterations").path("i") @@ -77,34 +80,32 @@ private WebResource getBaseServiceResource(Client client) { public Resource getResource(String idNoSlash, Set extensions) { Client client = factory.getClient(); - WebResource webResource = + WebTarget webResource = getBaseServiceResource(client) .path(idNoSlash) - .queryParams(ClientUtil.asMultivaluedMap( - "ext", extensions)); - return webResource.get(Resource.class); + .queryParam("ext", extensions.toArray()); + return webResource.request(MediaType.APPLICATION_XML_TYPE) + .get(Resource.class); } public String putResource(String idNoSlash, Resource resource, Set extensions, boolean copyTrans) { Client client = factory.getClient(); - CacheResponseFilter filter = new CacheResponseFilter(); - client.addFilter(filter); - WebResource webResource = getBaseServiceResource(client) + WebTarget webResource = getBaseServiceResource(client) .path(idNoSlash) - .queryParams(ClientUtil.asMultivaluedMap( - "ext", extensions)) + .queryParam("ext", extensions.toArray()) .queryParam("copyTrans", String.valueOf(copyTrans)); - webResource.put(resource); - client.removeFilter(filter); - return filter.getEntity(String.class); + Response response = webResource.request(MediaType.APPLICATION_XML_TYPE) + .put(Entity.entity(resource, MediaType.APPLICATION_XML_TYPE)); + response.bufferEntity(); + return response.readEntity(String.class); } public String deleteResource(String idNoSlash) { Client client = factory.getClient(); - WebResource webResource = getBaseServiceResource(client); - return webResource.path(idNoSlash).delete(String.class); + WebTarget webResource = getBaseServiceResource(client); + return webResource.path(idNoSlash).request().delete(String.class); } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/StatisticsResourceClient.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/StatisticsResourceClient.java index 28f3f3ea..c5edef77 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/StatisticsResourceClient.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/StatisticsResourceClient.java @@ -22,17 +22,13 @@ package org.zanata.rest.client; import java.net.URI; -import java.util.ArrayList; -import java.util.List; import javax.ws.rs.DefaultValue; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; import org.zanata.rest.dto.stats.ContainerTranslationStatistics; import org.zanata.rest.dto.stats.contribution.ContributionStatistics; import org.zanata.rest.service.StatisticsResource; -import com.google.common.collect.Lists; -import com.sun.jersey.api.client.WebResource; - -import static org.zanata.rest.client.ClientUtil.asMultivaluedMap; /** * @author Patrick Huang toLocaleList(String[] locales) { - List localesList; - if (locales == null) { - localesList = Lists.newArrayList(); - } else { - localesList = Lists.newArrayList(locales); - } - return localesList; + .queryParam("detail", includeDetails) + .queryParam("word", includeWordStats) + .queryParam("locale", (Object[]) locales); + return webResource.request(MediaType.APPLICATION_XML_TYPE) + .get(ContainerTranslationStatistics.class); } @Override public ContainerTranslationStatistics getStatistics(String projectSlug, String iterationSlug, String docId, @DefaultValue("false") boolean includeWordStats, String[] locales) { - WebResource webResource = - factory.getClient().resource(baseUri).path("stats") + WebTarget webResource = + factory.getClient().target(baseUri).path("stats") .path("proj") .path(projectSlug) .path("iter") @@ -88,16 +74,16 @@ public ContainerTranslationStatistics getStatistics(String projectSlug, .path("doc") .path(docId) .queryParam("word", String.valueOf(includeWordStats)) - .queryParams(asMultivaluedMap("locale", - toLocaleList(locales))); - return webResource.get(ContainerTranslationStatistics.class); + .queryParam("locale", (Object[]) locales); + return webResource.request(MediaType.APPLICATION_XML_TYPE) + .get(ContainerTranslationStatistics.class); } @Override public ContributionStatistics getContributionStatistics(String projectSlug, String versionSlug, String username, String dateRange, boolean includeAutomatedEntry) { - WebResource webResource = - factory.getClient().resource(baseUri).path("stats") + WebTarget webResource = + factory.getClient().target(baseUri).path("stats") .path("project") .path(projectSlug) .path("version") @@ -105,7 +91,8 @@ public ContributionStatistics getContributionStatistics(String projectSlug, .path("contributor") .path(username) .path(dateRange) - .queryParam("includeAutomatedEntry", String.valueOf(includeAutomatedEntry)); - return webResource.get(ContributionStatistics.class); + .queryParam("includeAutomatedEntry", includeAutomatedEntry); + return webResource.request(MediaType.APPLICATION_JSON_TYPE) + .get(ContributionStatistics.class); } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/TraceDebugFilter.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/TraceDebugFilter.java index 3ea3e3f0..a48c4ce2 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/TraceDebugFilter.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/TraceDebugFilter.java @@ -21,9 +21,14 @@ package org.zanata.rest.client; import java.io.ByteArrayInputStream; +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.slf4j.Logger; @@ -31,10 +36,6 @@ 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 @@ -46,59 +47,19 @@ * */ @Provider -public class TraceDebugFilter extends ClientFilter { +public class TraceDebugFilter implements ClientRequestFilter, + ClientResponseFilter { private static final Logger log = LoggerFactory .getLogger(TraceDebugFilter.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) { + private String getPayloadAsString(ClientResponseContext response) { ByteArrayInputStream entityInputStream = null; try { entityInputStream = - (ByteArrayInputStream) response.getEntityInputStream(); + (ByteArrayInputStream) response.getEntityStream(); int available = entityInputStream.available(); byte[] data = new byte[available]; entityInputStream.read(data); @@ -140,4 +101,44 @@ private String maskHeaderValues(List headerValues) { return maskedList.toString(); } + + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + if (!logHttp && !log.isTraceEnabled()) { + return; + } + log(">> REST Request: " + requestContext.getMethod() + " => " + + requestContext.getUri()); + + // Log before sending a request + for (String key : requestContext.getHeaders().keySet()) { + String headerVal = + requestContext.getHeaders().get(key).toString(); + if (key.equals(RestConstant.HEADER_API_KEY)) { + headerVal = + this.maskHeaderValues( + requestContext.getHeaders() + .get(key)); + } + + log(">> Header: " + key + " = " + headerVal); + } + log(">> body: " + requestContext.getEntity()); + } + + @Override + public void filter(ClientRequestContext requestContext, + ClientResponseContext responseContext) throws IOException { + if (!logHttp && !log.isTraceEnabled()) { + return; + } + // log after a response has been received + log("<< REST Response: " + responseContext.getStatus() + + ":" + responseContext.getStatusInfo()); + for (String key : responseContext.getHeaders().keySet()) { + log("<< Header: " + key + " = " + + responseContext.getHeaders().get(key)); + } + log(">> Body: " + getPayloadAsString(responseContext)); + } } diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/TransDocResourceClient.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/TransDocResourceClient.java index dd9fe2f2..cc10fc86 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/TransDocResourceClient.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/TransDocResourceClient.java @@ -23,18 +23,13 @@ import java.net.URI; import java.util.Set; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.PathParam; -import javax.ws.rs.QueryParam; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; import org.zanata.common.LocaleId; -import org.zanata.rest.dto.resource.TranslationsResource; -import com.sun.jersey.api.client.Client; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.WebResource; - -import static org.zanata.rest.client.ClientUtil.asMultivaluedMap; /** * This "implements" caller methods to endpoints in TranslatedDocResource. @@ -56,24 +51,25 @@ public class TransDocResourceClient { baseUri = factory.getBaseUri(); } - public ClientResponse getTranslations( - @PathParam("id") String idNoSlash, - @PathParam("locale") LocaleId locale, - @QueryParam("ext") Set extensions, - @QueryParam("skeletons") boolean createSkeletons, - @HeaderParam(HttpHeaders.IF_NONE_MATCH) String eTag) { + public Response getTranslations( + String idNoSlash, + LocaleId locale, + Set extensions, + boolean createSkeletons, + String eTag) { Client client = factory.getClient(); return getBaseServiceResource(client) .path(idNoSlash) .path("translations").path(locale.getId()) - .queryParams(asMultivaluedMap("ext", extensions)) + .queryParam("ext", extensions.toArray()) .queryParam("skeletons", String.valueOf(createSkeletons)) + .request(MediaType.APPLICATION_XML_TYPE) .header(HttpHeaders.IF_NONE_MATCH, eTag) - .get(ClientResponse.class); + .get(); } - private WebResource getBaseServiceResource(Client client) { - return client.resource(baseUri) + private WebTarget getBaseServiceResource(Client client) { + return client.target(baseUri) .path("projects").path("p") .path(project) .path("iterations").path("i") diff --git a/zanata-rest-client/src/test/java/org/zanata/rest/client/ApiKeyHeaderFilterTest.java b/zanata-rest-client/src/test/java/org/zanata/rest/client/ApiKeyHeaderFilterTest.java index 8a3fc60a..5ae641f3 100644 --- a/zanata-rest-client/src/test/java/org/zanata/rest/client/ApiKeyHeaderFilterTest.java +++ b/zanata-rest-client/src/test/java/org/zanata/rest/client/ApiKeyHeaderFilterTest.java @@ -24,7 +24,10 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.when; +import javax.ws.rs.client.ClientRequestContext; import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.Request; +import javax.ws.rs.core.Response; import org.hamcrest.Matchers; import org.junit.Before; @@ -32,8 +35,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.zanata.rest.RestConstant; -import com.sun.jersey.api.client.ClientRequest; -import com.sun.jersey.api.client.ClientResponse; /** * @author Sean Flanigan headerMap = new MultivaluedHashMap<>(); when(mockRequest.getHeaders()).thenReturn(headerMap); // - filter.handle(mockRequest); + filter.filter(mockRequest); assertThat(headerMap.getFirst(RestConstant.HEADER_USERNAME).toString(), Matchers.equalTo(username)); diff --git a/zanata-rest-client/src/test/java/org/zanata/rest/client/FileResourceClientTest.java b/zanata-rest-client/src/test/java/org/zanata/rest/client/FileResourceClientTest.java index caa0d687..e9be84ec 100644 --- a/zanata-rest-client/src/test/java/org/zanata/rest/client/FileResourceClientTest.java +++ b/zanata-rest-client/src/test/java/org/zanata/rest/client/FileResourceClientTest.java @@ -171,7 +171,7 @@ private String calculateFileHash(File srcFile) { public void testDownloadSourceFile() throws IOException { InputStream inputStream = client.downloadSourceFile("about-fedora", "master", "pot", - "About-Fedora").getEntity(InputStream.class); + "About-Fedora").readEntity(InputStream.class); PoReader2 reader = new PoReader2(); Resource resource = reader.extractTemplate(new InputSource(inputStream), @@ -183,7 +183,7 @@ public void testDownloadSourceFile() throws IOException { public void testDownloadTranslationFile() { InputStream inputStream = client.downloadTranslationFile("about-fedora", "master", "es", - "po", "About-Fedora").getEntity(InputStream.class); + "po", "About-Fedora").readEntity(InputStream.class); PoReader2 reader = new PoReader2(); TranslationsResource translationsResource = reader.extractTarget(new InputSource(inputStream)); diff --git a/zanata-rest-client/src/test/java/org/zanata/rest/client/TransDocResourceClientTest.java b/zanata-rest-client/src/test/java/org/zanata/rest/client/TransDocResourceClientTest.java index 2ad03c99..2660a713 100644 --- a/zanata-rest-client/src/test/java/org/zanata/rest/client/TransDocResourceClientTest.java +++ b/zanata-rest-client/src/test/java/org/zanata/rest/client/TransDocResourceClientTest.java @@ -52,7 +52,7 @@ public void testGetTranslations() { TranslationsResource translations = client.getTranslations("test", LocaleId.DE, Sets.newHashSet("gettext", "comment"), true, "abc") - .getEntity(TranslationsResource.class); + .readEntity(TranslationsResource.class); assertThat(translations.getTextFlowTargets(), Matchers.hasSize(1)); }