Why a RESTful web service can not call semaphore.acquire() properly? - java

I have a web service with the following methods code:
private static Semaphore reacted = new Semaphore(0);
#Path("/p1")
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public UserDefinedClass postMethod1( UserDefinedClass udc) {
If (Condition A)
semaphore.acquire();
System.out.println("Test");
UserDefinedClass u = new UserDefinedClass(udc);
return u;
}
#Path("/p2")
#POST
#Consumes(MediaType.APPLICATION_JSON)
public void postMethod2(UserDefinedClass udc) throws IOException {
...
reacted.release();
}
If Condition A does not occur, the service replies correctly to the calling environment (let's name it as CE), however, if Condition A is true, the method postMethod1 blocks waiting for somebody to invoke postMethod2.
If somebody calls postMethod2 (within 1 min from CE call to postMethod1). postMethod1 gets unblocked, however, the code below semaphore.acquire(); never gets executed and the "Test" message is not printed out rather I get the following error in CE:
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=text/html;charset=utf-8, type=class...
Please note that if Condition A was not true, no error is shown in CE. That means the issue is not with the method definition rather it is because the method's thread goes into the wait state waiting for the semaphore.
The CE code is:
UserDefinedClass udc = new UserDefinedClass();
ClientConfig config = new ClientConfig(JacksonJsonProvider.class);
Client client = ClientBuilder.newClient(config);
String targetUrl = "http://localhost:8080/myApp";
WebTarget target = client.target(targetUrl);
Invocation.Builder invocationBuilder = target.path("rest").
path("p1").
request(MediaType.APPLICATION_JSON);
Response response = invocationBuilder.post(Entity.entity(udc, MediaType.APPLICATION_JSON));
UserDefinedClass u = response.readEntity(UserDefinedClass.class);
So what could be the issue?!

I don't know how to do it in your scripting language but the content type text/html is wrong.
I am also not sure if it's the response or request part but it does not match or properly set APPLICATION_JSON.
You should be easily able to solve this by investigating the real network traffic (I use ngrep for that, but others prefer tcpdump).

Related

Asynchronous controller and method in Spring

I have a controller which receives a request to check status of a game, I want the whole thing to be done asynchronously. The controller seems to be working asynchronous, however postman hangs when I do the post request.
Here is my controller:
#RequestMapping(value = "/status", method = RequestMethod.POST, consumes="application/json")
private Callable<Byte> getStatus(#RequestBody final Matrix board){
System.out.println("Entering controller");
Callable<Byte> asyncResult = new Callable<Byte>() {
#Override
public Byte call() throws Exception {
return status.checkWinner(board);
}
};
System.out.println("Leaving controller");
return asyncResult ;
}
and here is my method in Status class:
public Byte checkWinner(Matrix board) {
System.out.println("start Slow work");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("finish Slow work");
return 0;
}
the program output shows this:
Entering controller
Leaving controller
start Slow work
finish Slow work
So i tried to put #Async on top of checkWinner method, postman shows 200 status ok, without showing the result 0 later on. And without the #Async annotation, postman (webpage) freezes for 5 seconds and the result 0 is shown.
This is an expected behaviour. The Callable returned is executed in a separate thread pool and the request thread is free for another processing. However, the connection to that specific client will be open and the client will be responded to only after callable is complete. Client will wait for the response or will timeout if the response is not obtained in the expected time.
The above model is only for server side load handling not client side. So this model will not work for you.
If you want the client to return, then you should return a jobid as the return value. Provide that client with a poll url to check for response. When the job is complete, return the response.

Jersey: immediate Response after asynchronous request

I try to understand the way asynchronous responses work with Jersey. I read chapter 10 of the Jersey documentation (https://jersey.java.net/documentation/latest/async.html) but it doesn't help with my problem. Also research here on stackoverflow didn't result in satisfying answers (that I can understand).
What I'm trying to do is similar to the one question in this post (Use http status 202 for asynchronous operations). I want to upload a large file to the server using a HTML form document. After the request is send to the server the web service should immediately response with status 202 and a URI where the file can be found after the request has finished.
After reading the post abive it seems possible but sadly no hints how to implement such a behavior where given.
I wrote a small web service to test the functionality:
#Path("/test/async/")
public class TestAsyncResponse {
#GET
#Path("get")
public Response asyncGet(#Suspended final AsyncResponse response) {
new Thread(new Runnable() {
#Override
public void run() {
DateFormat df = new SimpleDateFormat("dd/MM/yy HH:mm:ss");
System.out.println("#### thread started: "
+ df.format(new Date()) + " ####");
String result = veryExpensiveOperation();
System.out.println("#### thread finished: "
+ df.format(new Date()) + " ####");
response.resume(result);
}
private String veryExpensiveOperation() {
try {
Thread.sleep(10000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
return "Woke up!";
}
}).start();
return Response.status(202).entity("Request accepted. " +
"Long running operation started")
.build();
}
}
The service works but as a response I get the "Woke Up!" message after the 10 second wait rather than the 202 response which seems logical because the AsyncResponse is the one that handles the response (as I understand it).
After reading the documentation I got the impression that this is suppose to happen because all Jersey does with the asynchronous server response is to outsource the thread from the response thread pool to another one to free processing time for more responses to the service.
So my two questions would be: Is my understanding correct and can I use the asynchronous server response to get the desired behavior?
I tried to start a new thread without the AsyncResponse and I get a NullPointerExceptionbecause Jersey already closed the response and thus closed the InputStream that contains the file data. Is this the expected behavior? This post (https://stackoverflow.com/a/17559684/1416602) seems to indicate that it might work.
Any response is greatly appreciated.
Greetings
Your question is mixing two topics.
From HTTP perspective, 202 is technically a completed request. And the result of the request is 202, server telling you it will do it on the side. You will have to make another HTTP request to get updated status.
From the perspective of your application, async means that you will execute the request in a separate thread (or other async way). But also, this means that you will not return a result, not even 202, until the other "veryExpensiveOperation" finishes. The whole point in jumping through this hoop is to free up the calling thread. Your web server has a limited number, e.g. 20, and if each of your requests took a very long time, all 20 would be hanging. Using #Suspended you transfer execution from the web server thread to some other means, (another thread in your case). This is really only the first step. The idea behind async servers is that even the veryExpensiveOperation is implemented in some async way so that waiting for a DB or a file does not occupy a whole thread.
I have been through the same pain recently. Jersey keeps claiming it supports Asynchronous REST calls, but I think it's being disingenuous.
And in fact, once I started to work out the correct way of doing this, Jersey actually got in the way.
private static ExecutorService executorService = Executors.newFixedThreadPool( Integer.valueOf( numberOfThreads ) );
#POST
#Path("async")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response async( #FormDataParam("file") InputStream inputStream,
#FormDataParam("file") FormDataContentDisposition des ) throws Throwable {
String uniqueID = UUID.randomUUID().toString();
executorService.execute( new Runnable() {
#Override
public void run() {
try {
// do long performing action
} catch (Exception ex) {
}
}
} );
return Response.accepted().location( getResultsURI( uniqueID ) ).build();
}
#GET
#Path("results/{uniqueID}")
#Produces("application/zip")
public Response results( #PathParam(value = "uniqueID ") String uniqueID ) {
// Check status of job
// If not finished...
if (notFinished) {
return Response.status( 202 ).location( getResultsURI( uniqueID ) )
.entity( status ).build();
}
return Response.ok( FileUtils.readFileToByteArray( zip.toFile() ) ).type( "application/zip" )
.header( "Content-Disposition", "attachment; filename=\"filename.zip\"" ).build();
}
protected URI getResultsURI( String uniqueID ) throws URISyntaxException {
return new URI( Constants.WS_VERSION + "/results/" + uniqueID );
}
The biggest pain was that when you set Response.location(), even if you set it to "./results" or "/results", Jersey expands it to the full URL. Which would be fine, except that it ignores any class-level #Path:
#Path(Constants.WS_VERSION)
public class MyEndpoint {
So instead of fighting it, I used the above code to at least make it correct. Ideally I'd like Jersey to leave the "Location" header alone.
Anyway - the above code is what I used (excluding the business logic bits ;) )

Java Servlet 3.0 server push: Sending data multiple times using same AsyncContext

Lead by several examples and questions answered here ( mainly
http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page=3 ), I want to have server sending the response multiple times to a client without completing the request. When request times out, I create another one and so on.
I want to avoid long polling, since I have to recreate request every time I get the response. (and that quite isn't what async capabilities of servlet 3.0 are aiming at).
I have this on server side:
#WebServlet(urlPatterns = {"/home"}, name = "async", asyncSupported = true)
public class CometServlet extends HttpServlet {
public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException {
AsyncContext ac = request.startAsync(request, response);
HashMap<String, AsyncContext> store = AppContext.getInstance().getStore();
store.put(request.getParameter("id"), ac);
}
}
And a thread to write to async context.
class MyThread extends Thread {
String id, message;
public MyThread(String id, String message) {
this.id = id;
this.message = message;
}
public void run() {
HashMap<String, AsyncContext> store = AppContext.getInstance().getStore();
AsyncContext ac = store.get(id);
try {
ac.getResponse().getWriter().print(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
But when I make the request, data is sent only if I call ac.complete(). Without it request will always timeout. So basically I want to have data "streamed" before request is completed.
Just to make a note, I have tried this with Jetty 8 Continuation API, I also tried with printing to OutputStream instead of PrintWriter. I also tried flushBuffer() on response. Same thing.
What am I doing wrong?
Client side is done like this:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8080/home', true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 3 || xhr.readyState == 4) {
document.getElementById("dynamicContent").innerHTML = xhr.responseText;
}
}
xhr.send(null);
Can someone at least confirm that server side is okay? :)
Your server-side and client-side code is indeed ok.
The problem is actually with your browser buffering text/plain responses from your web-server.
This is the reason you dont see this issue when you use curl.
I took your client-side code and I was able to see incremental responses, with only just one little change:
response.setContentType("text/html");
The incremental responses showed up immediately regardless of their size.
Without that setting, when my output was a small message, it was considered as text/plain and wasnt showing up at the client immediately. When I kept adding more and more to the client responses, it got accumulated until the buffer size reached about 1024 bytes and then the whole thing showed up on the client side. After that point, however, the small increments showed up immediately (no more accumulation).
I know this is a bit old, but you can just flushBuffer on the response as well.

How to mock Jersey REST client to throw HTTP 500 responses?

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.
}
}
}

Can I wrap all JAX-RS requests with custom pre-dispatch, post-dispatch and error-handler code?

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.

Categories