We currently have some trouble on a productive server as it consumes way too much memory. One of the leaks could come from the jersey client. I found the following two other questions and a how to:
How to correctly share JAX-RS 2.0 client
Closing JAX RS Client/Response
https://blogs.oracle.com/japod/entry/how_to_use_jersey_client
What I get from it, I should reuse the Client and potentially also the WebTargets?
Also closing responses is advised, but how can I do this with .request()?
Code example, this is getting called about 1000 times per hour with different paths:
public byte[] getDocument(String path) {
Client client = ClientBuilder.newClient();
WebTarget target = client.target(config.getPublishHost() + path);
try {
byte[] bytes = target.request().get(byte[].class);
LOGGER.debug("Document size in bytes: " + bytes.length);
return bytes;
} catch (ProcessingException e) {
LOGGER.error(Constants.PROCESSING_ERROR, e);
throw new FailureException(Constants.PROCESSING_ERROR, e);
} catch (WebApplicationException e) {
LOGGER.error(Constants.RESPONSE_ERROR, e);
throw new FailureException(Constants.RESPONSE_ERROR, e);
} finally {
client.close();
}
}
So my question is how to properly use the API to prevent leaks for the above example?
Client instances should be reused
Client instances are heavy-weight objects that manage the underlying client-side communication infrastructure. Hence initialization as well as disposal of a Client instance may be a rather expensive operation.
The documentation advises to create only a small number of Client instances and reuse them when possible. It also states that Client instances must be properly closed before being disposed to avoid leaking resources.
WebTarget instances could be reused
You could reuse WebTarget instances if you perform multiple requests to the same path. And reusing WebTarget instances is recommended if they have some configuration.
Response instances should be closed if you don't read the entity
Response instances that contain an un-consumed entity input stream should be closed. This is typical for scenarios where only the response headers and the status code are processed, ignoring the response entity. See this answer for more details on closing Response instances.
Improving your code
For the situation mentioned in your question, you want you ensure that the Client instance is reused for all getDocument(String) method invocations.
For instance, if your application is CDI based, create a Client instance when the bean is constructed and dispose it before its destruction. In the example below, the Client instance is stored in a singleton bean:
#Singleton
public class MyBean {
private Client client;
#PostConstruct
public void onCreate() {
this.client = ClientBuilder.newClient();
}
...
#PreDestroy
public void onDestroy() {
this.client.close();
}
}
You don't need to (or maybe you can't) reuse the WebTarget instance (the requested path changes for each method invocation). And the Response instance is automatically closed when you read the entity into a byte[].
Using a connection pool
A connection pool can be a good performance improvement.
As mentioned in my older answer, by default, the transport layer in Jersey is provided by HttpURLConnection. This support is implemented in Jersey via HttpUrlConnectorProvider. You can replace the default connector if you want to and use a connection pool for better performance.
Jersey integrates with Apache HTTP Client via the ApacheConnectorProvider. To use it, add the following dependecy:
<dependency>
<groupId>org.glassfish.jersey.connectors</groupId>
<artifactId>jersey-apache-connector</artifactId>
<version>2.26</version>
</dependency>
And then create your Client instance as following:
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(5);
ClientConfig clientConfig = new ClientConfig();
clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
clientConfig.connectorProvider(new ApacheConnectorProvider());
Client client = ClientBuilder.newClient(clientConfig);
For additional details, refer to Jersey documentation about connectors.
Use the following example in this link to close Response on completed method: https://jersey.github.io/documentation/latest/async.html#d0e10209
final Future<Response> responseFuture = target().path("http://example.com/resource/")
.request().async().get(new InvocationCallback<Response>() {
#Override
public void completed(Response response) {
System.out.println("Response status code "
+ response.getStatus() + " received.");
//here you can close the response
}
#Override
public void failed(Throwable throwable) {
System.out.println("Invocation failed.");
throwable.printStackTrace();
}
});
tip 1 (Response or String):
You can close the response only when it is from type of Response class, not : String.
tip 2 (Auto-closing):
Referring to this question, When you read the entity, the response will be closed automatically:
String responseAsString = response.readEntity(String.class);
tip 3 (connection pooling):
Referring to this question, you can use connection-pools to have better performance. example:
public static JerseyClient getInstance() {
return InstanceHolder.INSTANCE;
}
private static class InstanceHolder {
private static final JerseyClient INSTANCE = createClient();
private static JerseyClient createClient() {
ClientConfig clientConfig = new ClientConfig();
clientConfig.property(ClientProperties.ASYNC_THREADPOOL_SIZE, 200);
clientConfig.property(ClientProperties.READ_TIMEOUT, 10000);
clientConfig.property(ClientProperties.CONNECT_TIMEOUT, 10000);
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(200);
connectionManager.setDefaultMaxPerRoute(100);
clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
clientConfig.connectorProvider(new ApacheConnectorProvider());
JerseyClient client = JerseyClientBuilder.createClient(clientConfig);
//client.register(RequestLogger.requestLoggingFilter);
return client;
}
}
ATTENTION! By using this solution, if you don't close the response, you can not send more than 100 requests to server (setDefaultMaxPerRoute(100))
Related
I have three or more types of request that come in form of JSON data and convert to object.
Let's say that there is a request:
{
"id":1,
"type":"0",
"url":
"http://stackoverflow.com"
}
And I want to build some sort of conncetion factory that allows me to get pages like that:
Request request = new Request(json);
Response response = request.execute();
Of course the execute method has different implementation for each of the request's types.
I have a prototype that is written in plain JavaSE and I want to migrate to Spring Framework and also get some feedback about my code if it has problems. First of all I built a SimpleRequest that just obtains the page and returns the body.
class SimpleRequest implements Request{
Package requestData;
#Override
public Connection.Response execute() throws IOException {
Connection.Response response = Jsoup
.connect(requestData.getUrl())
.execute();
return response;
}
public void bind(Package requestData){
this.requestData = requestData;
}
}
This method just fetch the page. Nothing interesting.
Also I have RequestTemplate that prepare request:
class RequestTemplate{
Package requestData;
RequestFactory requestFactory = new RequestFactory();
Request request;
public RequestTemplate(Package requestData){
this.requestData = requestData;
try {
request = requestFactory.getRequestInstance(requestData.getType());
request.bind(requestData);
}catch (Exception e){
e.printStackTrace();
}
}
public Connection.Response execute(){
Connection.Response connection = null;
try{
connection = request.execute();
}catch (Exception e){
e.printStackTrace();
}
return connection;
}
}
This method obtains an object based of RequestType;
And of course I have RequestFactory that has a description of objects and create new Instances of them.
class RequestFactory{
public Request getRequestInstance(RequestType type) throws Exception {
switch (type){
case SIMPLE:
return new SimpleRequest();
default:
throw new Exception("Error");
}
}}
So we check the RequestType type matching with the enum list and return new instance.
I also what to implement something like that in my small project that are based on Spring Framework and there are two issues.
As I understand the code above is a bit messy and has some performance problems. I think that I'll use the code to serve lots of connection so that I have to optimize it somehow because of memory limit and so on.
Integration with Spring. It's a framework so I think there should be some features that could make my life easier. I've read about FactoryBean, but haven't caught how to wire it with my task. As I mentioned above that the code is a bit messy and i think that i created to much abstraction.
Thanks.
I am trying my hand at using http.core & client 4.3. In general it works well, and is quite pleasant to deal with. However, I am getting a ConnectionClosedException on one of my transfers and I can't see why. Others work just fine as far as I can tell.
Everything follows the examples in a pretty straight forward way. If it didn't, it was re-written to as much as possible in an effort to get rid of this.
There are 2 servers, both running the same code [A & B]
A HttpClient sends a request "AX" (POST) to B
B HttpService receives the "AX" post, processes it
B HttpClient sends a reply "BR" (POST) to A on a different port
Later This should happen after the connection to A is closed, or as close as possible
Right now the code doesn't actually care
A receives the reply from B (on a different thread) and does things
In the problem scenario, A is running as the server, and B is sending a POST. Sorry it isn't always clear, since in one transaction both sides end up running server and client code.
A Sends POST to B:8080. Get back a proper response inline, everything ok.
POST Connection to B:8080 gets closed properly
B sends new POST (like an ACK) to A (ex... B:53991 => A:9000).
A Processs everything. No issues
A rasies ConnectionClosedException
Since I don't why it's happening for sure, I tried to put everything I think is relevant in there. My only thought right now is that it has something to with making sure I add/change connection control headers, but I can't see how that would affect anything.
Stack Trace from machine "A", when the reply from B comes
org.apache.http.ConnectionClosedException: Client closed connection
at org.apache.http.impl.io.DefaultHttpRequestParser.parseHead(DefaultHttpRequestParser.java:133)
at org.apache.http.impl.io.DefaultHttpRequestParser.parseHead(DefaultHttpRequestParser.java:54)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:260)
at org.apache.http.impl.DefaultBHttpServerConnection.receiveRequestHeader(DefaultBHttpServerConnection.java:131)
at org.apache.http.protocol.HttpService.handleRequest(HttpService.java:307)
at com.me.HttpRequestHandlerThread.processConnection(HttpRequestHandlerThread.java:45)
at com.me.net.http.HttpRequestHandlerThread.run(HttpRequestHandlerThread.java:70)
com.me.ExceptionHolder: Client closed connection
at com.me.log.Log.logIdiocy(Log.java:77)
at com.me.log.Log.error(Log.java:54)
at com.me.net.http.HttpRequestHandlerThread.run(HttpRequestHandlerThread.java:72)
Caused by: org.apache.http.ConnectionClosedException: Client closed connection
at org.apache.http.impl.io.DefaultHttpRequestParser.parseHead(DefaultHttpRequestParser.java:133)
at org.apache.http.impl.io.DefaultHttpRequestParser.parseHead(DefaultHttpRequestParser.java:54)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:260)
at org.apache.http.impl.DefaultBHttpServerConnection.receiveRequestHeader(DefaultBHttpServerConnection.java:131)
at org.apache.http.protocol.HttpService.handleRequest(HttpService.java:307)
at com.me.net.http.HttpRequestHandlerThread.processConnection(HttpRequestHandlerThread.java:45)
at com.me.net.http.HttpRequestHandlerThread.run(HttpRequestHandlerThread.java:70)
This is the code running on B, the "client" in this scenario. It is trying to POST the reply acknowledging that the first POST from A was received properly. There really isn't much to transmit, and the response should only be an HTTP 200:
try (CloseableHttpClient client = HttpClients.createDefault()) {
final HttpPost post = new HttpPost(url);
post.setHeaders(/* create application specific headers */);
ByteArrayEntity entity = new ByteArrayEntity(IOUtils.toByteArray(myStream));
post.setEntity(entity);
ResponseHandler<Void> responseHandler = new ResponseHandler<Void>() {
#Override
public Void handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
StatusLine status = response.getStatusLine();
if (!NetUtil.isValidResponseCode(response)) {
throw new ClientProtocolException("Unexpected Error! Oops");
}
// consume the response, if there is one, so the connection will close properly
EntityUtils.consumeQuietly(response.getEntity());
return null;
}
};
try {
client.execute(post, responseHandler);
} catch (ClientProtocolException ex) {
// logic to queue a resend for 10 minutes later. not triggered
throw ex;
}
}
On A: This is called async because the response doesn't come in over the same http connection.
The main request handler does a lot more work, but it is amazing how little code there is actually controlling the HTTP in the handler/server side. Great library... that I am misusing somehow. This is the actual handler, with everything simplified a bit, validation removed, etc.
public class AsyncReceiverHandler implements HttpRequestHandler {
#Override
public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
// error if not post, other logic. not touching http. no errors
DefaultBHttpServerConnection connection = (DefaultBHttpServerConnection) context.getAttribute("connection");
Package pkg = NetUtil.createPackageFrom(connection); // just reads sender ip/port
NetUtil.copyHttpHeaders(request, pkg);
try {
switch (recieive(request, pkg)) {
case EH_OK:
response.setStatusCode(HttpStatus.SC_OK);
break;
case OHNOES_BAD_INPUT:
response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
response.setEntity(new StringEntity("No MDN entity found in request body"));
// bunch of other cases, but are not triggered. xfer was a-ok
}
} catch (Exception ex) {
//log
}
}
private MyStatus receiveMdn(HttpRequest request, Package pkg) throws Exceptions..., IOException {
// validate request, get entity, make package, no issues
HttpEntity resEntity = ((HttpEntityEnclosingRequest) request).getEntity();
try {
byte[] data = EntityUtils.toByteArray(resEntity);
// package processing logic, validation, fairly quick, no errors thrown
} catch (Exceptions... ex) {
throw ExceptionHolder(ex);
}
}
}
This is the request handler thread. This and the server are taken pretty much verbatim from the samples. The service handler just starts the service and accept()s the socket. When it gets one, it creates a new copy of this, and calls start():
public HttpRequestHandlerThread(final HttpService httpService, final HttpServerConnection conn, HttpReceiverModule ownerModule) {
super();
this.httpService = httpService;
this.conn = (DefaultBHttpServerConnection) conn;
}
private void processConnection() throws IOException, HttpException {
while (!Thread.interrupted() && this.conn.isOpen()) {
/* have the service create a handler and pass it the processed request/response/context */
HttpContext context = new BasicHttpContext(null);
this.httpService.handleRequest(this.conn, context);
}
}
#Override
public void run() {
// just runs the main logic and reports exceptions.
try {
processConnection();
} catch (ConnectionClosedException ignored) {
// logs error here (and others).
} finally {
try { this.conn.shutdown(); } catch (IOException ignored) {}
}
}
}
Well, this seems stupid now, and really obvious. I ignored the issue for a while and moved on to other things, and the answer bubbled up from the subconscious, as they will.
I added this header back and it all cleared up:
post.setHeader("Connection", "close, TE")
Somehow the line to set the Connection header got removed, probably accidentally by me. A lot of them get set, and it was still there, just wrong in this code path. Basically, the server expects this connection to close immediately but the header was reverting to the default keep-alive. Since the client closes the connection as soon as it is done with it this was surprising the server, who was told otherwise, and rightly compliained :D In the reverse path everything was OK.
Since I had just changed the old stack to use HttpComponents I didn't look at headers and such, and I just assumed I was using it wrong. The old stack didn't mind it.
I'm new to Netty, and am looking at using it to make a simple http proxy server that receives requests from a client, forwards the requests to another server, and then copies the response back to the response for the original request. One extra requirement is that I be able to support a timeout, so that if the proxied server takes too long to respond the proxy will respond by itself and close the connection to the proxied server.
I've already implemented such an application using Jetty, but with Jetty I need to use too many threads to keep inbound requests from getting blocked (this is a lightweight app that uses very little memory or cpu, but the latency of the proxied server is high enough that bursts in traffic cause either queueing in the proxy server, or require too many threads).
According to my understanding, I can use Netty to build a pipeline in which each stage performs a small amount of computation, then releases it's thread and waits until data is ready for the next stage in the pipeline to be executed.
My question is, is there a simple example of such an application? What I have so far is a simple modification of the server code for the basic Netty tutorial, but it lacks all support for a client. I saw the netty client tutorial, but am not sure how to mix code from the two to create a simple proxy app.
public static void main(String[] args) throws Exception {
ChannelFactory factory =
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
ServerBootstrap bootstrap = new ServerBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
return Channels.pipeline(
new HttpRequestDecoder(),
new HttpResponseEncoder(),
/*
* Is there something I can put here to make a
* request to another server asynchronously and
* copy the result to the response inside
* MySimpleChannelHandler?
*/
new MySimpleChannelHandler()
);
}
});
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.bind(new InetSocketAddress(8080));
}
private static class MySimpleChannelHandler extends SimpleChannelHandler {
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
HttpRequest request = (HttpRequest) e.getMessage();
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
response.setContent(request.getContent());
Channel ch = e.getChannel();
ChannelFuture f = ch.write(response);
f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
Channel ch = future.getChannel();
ch.close();
}
});
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
e.getCause().printStackTrace();
Channel ch = e.getChannel();
ch.close();
}
}
you would have to look at LittleProxy to see how they did it as it is written on top of Netty.
I am writing a Java class that uses Jersey under the hood to send an HTTP request to a RESTful API (3rd party).
I would also like to write a JUnit test that mocks the API sending back HTTP 500 responses. Being new to Jersey, it is tough for me to see what I have to do to mock these HTTP 500 responses.
So far here is my best attempt:
// The main class-under-test
public class MyJerseyAdaptor {
public void send() {
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
String uri = UriBuilder.fromUri("http://example.com/whatever").build();
WebResource service = client.resource(uri);
// I *believe* this is where Jersey actually makes the API call...
service.path("rest").path("somePath")
.accept(MediaType.TEXT_HTML).get(String.class);
}
}
#Test
public void sendThrowsOnHttp500() {
// GIVEN
MyJerseyAdaptor adaptor = new MyJerseyAdaptor();
// WHEN
try {
adaptor.send();
// THEN - we should never get here since we have mocked the server to
// return an HTTP 500
org.junit.Assert.fail();
}
catch(RuntimeException rte) {
;
}
}
I am familiar with Mockito but have no preference in mocking library. Basically if someone could just tell me which classes/methods need to be mocked to throw a HTTP 500 response I can figure out how to actually implement the mocks.
Try this:
WebResource service = client.resource(uri);
WebResource serviceSpy = Mockito.spy(service);
Mockito.doThrow(new RuntimeException("500!")).when(serviceSpy).get(Mockito.any(String.class));
serviceSpy.path("rest").path("somePath")
.accept(MediaType.TEXT_HTML).get(String.class);
I don't know jersey, but from my understanding, I think the actual call is done when get() method is invoked.
So you can just use a real WebResource object and replace the behavior of the get(String) method to throw the exception instead of actually execute the http call.
I'm writing a Jersey web application... and we throw WebApplicationException for HTTP error responses. You can simply pass the response code as the constructor-parameter. For example,
throw new WebApplicationException(500);
When this exception is thrown server-side, it shows up in my browser as a 500 HTTP response.
Not sure if this is what you want... but I thought the input might help! Best of luck.
I was able to simulate a 500 response with the following code:
#RunWith(MockitoJUnitRunner.class)
public class JerseyTest {
#Mock
private Client client;
#Mock
private WebResource resource;
#Mock
private WebResource.Builder resourceBuilder;
#InjectMocks
private Service service;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void jerseyWith500() throws Exception {
// Mock the client to return expected resource
when(client.resource(anyString())).thenReturn(resource);
// Mock the builder
when(resource.accept(MediaType.APPLICATION_JSON)).thenReturn(resourceBuilder);
// Mock the response object to throw an error that simulates a 500 response
ClientResponse c = new ClientResponse(500, null, null, null);
// The buffered response needs to be false or else we get an NPE
// when it tries to read the null entity above.
UniformInterfaceException uie = new UniformInterfaceException(c, false);
when(resourceBuilder.get(String.class)).thenThrow(uie);
try {
service.get("/my/test/path");
} catch (Exception e) {
// Your assert logic for what should happen here.
}
}
}
I have a number of classes exposed as JAX-RS request "handlers", using javax.ws.rs.Path annotations. I want to add certain actions before every request and after each request. Also, I need to create a global application-wide exception handler, which will catch everything thrown by these handlers and protocol.
Is it possible to achieve this with standard JAX-RS without creating of a custom class inherited from com.sun.jersey.spi.container.servlet.ServletContainer (I'm using Jersey).
You can also use ExceptionMappers. This mechanism which catch the exception thrown by your service and convert it to the appropriate Response:
#Provider
public class PersistenceMapper implements ExceptionMapper<PersistenceException> {
#Override
public Response toResponse(PersistenceException arg0) {
if(arg0.getCause() instanceof InvalidDataException) {
return Response.status(Response.Status.BAD_REQUEST).build();
} else {
...
}
}
}
For more information see:
JAX-RS using exception mappers
You could create a proxy RESTful service and use this as the entry point to all your other RESTful services. This proxy can receive requests, do any pre-processing, call the RESTful service required, process the response and then return something to the caller.
I have a set up like this in a project I've been working on. The proxy performs functions like authentication, authorisation and audit logging. I can go into further details if you like.
Edit:
Here is an idea of how you might want to implement a proxy that supports GET requests;
#Path("/proxy")
public class Proxy
{
private Logger log = Logger.getLogger(Proxy.class);
#Context private UriInfo uriInfo;
#GET
#Path("/{webService}/{method}")
public Response doProxy(#Context HttpServletRequest req,
#PathParam("webService") String webService,
#PathParam("method") String method)
{
log.debug("log request details");
//implement this method to work out the URL of your end service
String url = constructURL(req, uriInfo, webService, method);
//Do any actions here before calling the end service
Client client = Client.create();
WebResource resource = client.resource(url);
try
{
ClientResponse response = resource.get(ClientResponse.class);
int status = response.getStatus();
String responseData = response.getEntity(String.class);
log.debug("log response details");
//Do any actions here after getting the response from the end service,
//but before you send the response back to the caller.
return Response.status(status).entity(responseData).build();
}
catch (Throwable t)
{
//Global exception handler here
//remember to return a Response of some kind.
}
}
You can use filters to read and modify all requests and responses.