Uploaded image for project: 'RESTEasy'
  1. RESTEasy
  2. RESTEASY-963

Resteasy Client does not properly handle Server exception, rendering Client inoperable

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Blocker Blocker
    • 3.0.5.Final
    • 3.0.4.Final
    • None
    • None

      INTRODUCTION

      This RestEeasy Test Program demonstrates issues with the RestEasy Client Framework.

      GETTING IT WORKING

      This is a small, multi-module Maven project that contains a Client and Server.
      First, you need to build everything, so at the top level (resteasy-client-test), run: mvn clean install
      Second, you will need to run the Server, so at the resteasy-server level, run: mvn jetty:run
      Finally, you need to run the Client, so at the resteasy-client level, run: mvn exec:java

      WHAT DOES IT DEMONSTRATE?

      The main issue that this is designed to highlight is the fact that the Resteasy Client Proxy does not handle an exception well from the server. It essentially renders the Client connection unusable and impairs further interaction with the server. This could be catastrophic to an application, hence it is important to raise this concern so that the Resteasy project can devise a solution.

      The Client Tester has a standard test where it will ask the Server for a response (essentially an echo). A test will make a number of attempts and each odd request will cause an Exception at the Server. The main difference between the tests is how the Client is created, and what parameters are used.

      The Client Tester runs 3 Test Scenarios against the simple Server:

      • Test 1: Using a standard Client (from ClientBuilder.newClient()), makes 4 attempts
      • Test 2: Using a pooled Client with a maximum of 3 connections, makes 5 attempts
      • Test 3: Using a pooled Client with a maximum of 1 connection, makes 3 attempts

      These scenarios seemed enough to illustrate what is going on, but feel free to tinker with your own scenarios.

      TEST 1

      We have a plain, vanilla, single connection Client.
      The first attempt is successful.
      The second attempt generates an exception (on the server). The Exception stack trace is:

      1647 [ClientTester.main()] ERROR ClientTester - Request threw an exception!
      javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
      	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.handleErrorStatus(ClientInvocation.java:170)
      	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:135)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:58)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:104)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:62)
      	at com.sun.proxy.$Proxy30.getContent(Unknown Source)
      	at ClientTester.testMyResource(ClientTester.java:28)
      	at ClientTester.main(ClientTester.java:47)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      	at java.lang.reflect.Method.invoke(Method.java:597)
      	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:297)
      	at java.lang.Thread.run(Thread.java:680)
      

      The third attempt generates another exception – this time because the Client object is in a bad state. The Exception stack trace is:

      1649 [ClientTester.main()] ERROR ClientTester - Request threw an exception!
      javax.ws.rs.ProcessingException: Unable to invoke request
      	at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:249)
      	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:388)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:102)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:62)
      	at com.sun.proxy.$Proxy30.getContent(Unknown Source)
      	at ClientTester.testMyResource(ClientTester.java:28)
      	at ClientTester.main(ClientTester.java:47)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      	at java.lang.reflect.Method.invoke(Method.java:597)
      	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:297)
      	at java.lang.Thread.run(Thread.java:680)
      Caused by: java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
      Make sure to release the connection before allocating another one.
      	at org.apache.http.impl.conn.BasicClientConnectionManager.getConnection(BasicClientConnectionManager.java:161)
      	at org.apache.http.impl.conn.BasicClientConnectionManager$1.getConnection(BasicClientConnectionManager.java:138)
      	at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:455)
      	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
      	at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
      	at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:245)
      	... 12 more
      

      The fourth, and final, attempt yields the same exception as the last attempt. All future requests are now impossible because the Client is in a bad state.

      The expected behavior is that the second attempt would not render the Client inoperable so that the third and future attempts would work.

      TEST 2

      We have a pooled Client with a maximum of 3 connections, and we make 5 attempts.
      The first attempt is successful.
      The second attempt generates an exception (on the server). The Exception stack trace is:

      javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
      	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.handleErrorStatus(ClientInvocation.java:170)
      	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:135)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:58)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:104)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:62)
      	at com.sun.proxy.$Proxy30.getContent(Unknown Source)
      	at ClientTester.testMyResource(ClientTester.java:28)
      	at ClientTester.main(ClientTester.java:51)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      	at java.lang.reflect.Method.invoke(Method.java:597)
      	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:297)
      	at java.lang.Thread.run(Thread.java:680)
      

      The third attempt is successful.
      The fourth attempt generates an exception (on the server). The Exception stack trace is the same as the second attempt.
      (Note that we now have 2 bad connections in the client pool.)
      The fifth attempt is successful – we still have 1 good connection available in the pool.

      This test creates a pool with 2 bad connections; more attempts will render the pool completely useless.
      The expected behavior is that the second attempt would not render the Client inoperable.

      TEST 3

      We have a pooled Client with a maximum of 1 connection, and we try to make 3 attempts.
      The first attempt is successful.
      The second attempt generates an exception (on the server). The Exception stack trace is:

      5792 [ClientTester.main()] ERROR ClientTester - Request threw an exception!
      javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error
      	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.handleErrorStatus(ClientInvocation.java:170)
      	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.extractResult(ClientInvocation.java:135)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.extractors.BodyEntityExtractor.extractEntity(BodyEntityExtractor.java:58)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:104)
      	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:62)
      	at com.sun.proxy.$Proxy30.getContent(Unknown Source)
      	at ClientTester.testMyResource(ClientTester.java:28)
      	at ClientTester.main(ClientTester.java:55)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      	at java.lang.reflect.Method.invoke(Method.java:597)
      	at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:297)
      	at java.lang.Thread.run(Thread.java:680)
      

      The third attempt is now stuck! No exception... Just stuck!

      The expected behavior is that the second attempt would not render the Client inoperable so that the third attempt would work.

            rsigal@redhat.com Ronald Sigal
            awhitford Anthony Whitford (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: