DeferredResult with ajax request with two request - java

I´m trying to use DeferredResult with an ajax request, but when I return the result my ajax request keeps waiting for response.
Here the client that make the long polling request
(function poll() {
var SUCCESS = 1;
var tenantName = $("#tenantName").val();
$.ajax({
method: "GET",
url: "url.do?subStep=" + subStep + "&tenantId=" + tenantName,
success: function (response) {
alert(response)
if (response.status === SUCCESS) {
bootbox.dialog({
size:"small",
message: "<div class='col-xs-offset-4'>" +
"<i class='fa fa-user'> Page has been modify by " + response.payload + " " +
"<a href='javascript:void(0)' onclick='reload()'>reload</a>" +
"</i>" +
"</div>"
});
}
}, dataType: "json", complete: poll, timeout: 60000
});
})();
Here my controller where I make a long polling request by Ajax every 30 seconds.
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public DeferredResult<JsonEntity> getSubStepStatus(#RequestParam("subStep") String subStep,
#RequestParam("tenantId") String tenantId) {
if (tenantsInStep.get(subStep) == null) {
initializeTenantsInStep(subStep);
}
if(!tenantsInStep.get(subStep).contains(tenantId)){
tenantsInStep.get(subStep).add(tenantId);
}
DeferredResult<JsonEntity> deferredResult = new DeferredResult<>();
tenantsDeferredInStep.put(tenantId, deferredResult);
return deferredResult;
}
And then when my application detect a POST/PUT ajax request invoke a request to this method of my controller that release the DeferredResults.
#RequestMapping(value = "/setModification", method = RequestMethod.GET)
#ResponseBody
public final Integer setModification(#RequestParam("subStep") String subStep,
#RequestParam("tenantId") String tenantId) {
for (String tenantInStepId : tenantsInStep.get(subStep)) {
if (!tenantId.equals(tenantInStepId)) {
JsonEntity<String> jsonEntity = new JsonEntity();
jsonEntity.setPayload(tenantId);
jsonEntity.setStatus(FeedbackActions.SUCCESS.getCode());
DeferredResult<JsonEntity> jsonEntityDeferredResult = tenantsDeferredInStep.get(tenantId);
tenantsInStep.remove(tenantInStepId);
jsonEntityDeferredResult.setResult(jsonEntity);
}
}
return FeedbackActions.SUCCESS.getCode();
}
This example has been done by two user with two browser to achieve this, but the first client that create the deferredResult dont receive the result when the second client invoke the deferredResult.setResult(bla), no alert on ajax code is invoked.
I´m doing something wrong?, I add the
<task:annotation-driven/>
And the
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
In my applicationContext and web.xml configuration
As an extra information I´m using on my local test Jetty
Regards.

Related

HTTP 403 Forbidden Jersey on Put Request

I am facing an 'HTTP 403 Forbidden' error while trying to consume PUT request of a restful resource from an angular client. I created this restful resource using jersey and I am using tomcat 7 as application server.
Here is my resource code:
#Path("/doc")
public class DocResource {
#PUT
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
#Path("file/upload")
public Response uploadFile(MultipartBody body, #QueryParam("ID") long ID) {
try {
Attachment attachment = body.getAttachment("file");
MultivaluedMap<String, String> headers = attachment.getHeaders();
String fileName = getFileName(headers);
DataHandler dataHandler = attachment.getDataHandler();
InputStream inputStream = dataHandler.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] tmp = new byte[4096];
int ret = 0;
while ((ret = inputStream.read(tmp)) > 0) {
bos.write(tmp, 0, ret);
}
// TODO - Save contents as process attachment
byte[] contents = bos.toByteArray();
return Response.ok(getDocumentService().createAttachment(ID, fileName, contents, attachment.getContentType()), MediaType.APPLICATION_JSON).build();
} catch (Exception e) {
return handleException(e, "failed to upload Attachement");
}
}
}
Here is my angular js snippet
this.uploadFile = function uploadFile(callback, ID, file) {
var baseRestURL="http://localhost:8080/rest/doc"
// resource query
var query ;
// create form data
var formData = new FormData();
formData.append('file', file);
// set up the resource
var resource = $resource(baseRestURL + '/file/upload', {
ID: ID
}, {
'ID': ID,
'upload': {
method: 'PUT',
headers: {
'Content-Type': 'multipart/form-data'
}
}
});
resource.upload(query, formData).$promise.then(function success(response) {
if (callback) callback(response);
}, function error() {
//TODO handle error
});
};
I want to notice that other type of http calls such as DELETE, POST and GET are working properly. I have only problems with PUT calls.
I had a similar issue, but both DELETE and PUT were not working for me - returned HTTP 403 error. After I searched I stumbled across this link, and it pointed out where I went wrong.
I had a CORS filter added in my web.xml as part of some other R&D i was doing, and forgot to remove it.
This was from the original web.xml
<servlet>
<servlet-name>jersey-serlvet</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.jaxrs.listing,
com.xxx.yyy.rest</param-value>
</init-param>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
org.glassfish.jersey.jackson.JacksonFeature;
org.apache.catalina.filters.CorsFilter
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Once I removed the org.apache.catalina.filters.CorsFilter it started to work for me!
Hope this helps!

Why does Spring MVC respond with 415 for an Ajax query requesting JSON?

I've read 3/4 posts on Stack plus many other examples to try figure this out but I've no clue ! Need some pointers please !!
Creating my first Ajax update through Spring-MVC and I keep getting a Status 415 being returned by my submission with The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request accept
JQuery... Version 3.1.1
function updateScore () {
$("div#results").append("<p>Posting User/Game ID " + this.id + " Value " + this.value + "</p>");
var prediction = {}
prediction["id"] = this.id;
prediction["value"] = this.value;
$.ajax({
type : "POST",
contentType : "application/json",
url : "/tournament/setPrediction.html",
data : JSON.stringify(prediction),
dataType : 'json',
timeout : 100000,
success : function(data) {
console.log("SUCCESS: ", data);
displayResult(data, "success");
},
error : function(e) {
console.log("ERROR: ", e);
displayResult(e, "error");
},
done : function(e) {
console.log("DONE");
displayResult(true, "done");
}
});
}
Controller... Spring version 4.3.5
#RestController
public class PredictionAjaxController {
#ResponseBody
#RequestMapping(value = "/setPrediction.html", consumes = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.POST, headers="Accept=application/json")
public Prediction setUserPrediction(#RequestBody PredictionPojo prediction) {
Prediction result = new Prediction();
System.out.println("AJAX call made in controller");
return result;
}
}
Finally a very simple POJO for the JSon to map to
public class PredictionPojo {
private String id;
private String value;
Getters & Setters... ()
}
I've added different things onto the controller now to try and resolve, didn't start with it all ! I'm completely confuddled !
Should be so simple...
DH
You have an error in your ajax call, you are sending a string instead of a JSON object. Also I don't think is necessary to specify the consumes and headers attributes in you #RequestMapping annotation in your setUserPrediction method, The PredictionAjaxController is already defined as a RestController. Your ajax should be:
$.ajax({
// .......
data : prediction,
// .......
});

How to read JSON data in RestWebservice from AJAX request

I am trying to send a JSON string from a HTML page using AJAX call to a RESTWebservice. The methods in the server gets invoked however I am not able to retrieve the JSON data that I have set in the browser through AJAX call. I am usng jersy for the REST services.
Here is my HTML code.
<body>
<script type="text/javascript">
var userConfig = {};
userConfig.user = "arin_12";
userConfig.fullName = "Arindam";
var data = JSON.stringify(userConfig);
alert(data);
var req = new XMLHttpRequest();
req.open('POST', 'http://localhost:8080/LiveHive2/rest/hello', true);
req.setRequestHeader('Content-Type','application/json;charset=UTF-8');
req.onreadystatechange = function () {
if(req.readyState === 4 && req.status === 200) {
if(req.responseText) {
alert('The saving of data is ' + req.responseText);
}
}
}
req.send(data);
</script>
index page
</body>
Here is my JavaCode in RestWebservice.
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String sayJSONHello2(UserConfig uc) {
System.out.println("req" + uc);
return "{\"Name\":\"Arindam\"}";
}
Web.xml looks like this.
<servlet>
<servlet-name>JerseyRESTService</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.vogella.jersey.first</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
So the body of the POST request will be
{
"user": "arin_12",
"fullName": "Arindam"
}
Write a Java class this JSON can be mappend to.
public class UserConfig {
private String user;
private String fullName;
// Constructor, Getter, Setter, ...
}
Then JAX-RS allows you to automatically convert the JSON to a class instance.
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String sayJSONHello2(UserConfig userConfig) {
System.out.println("got UserConfig: " + userConfig);
return "{\"Name\":\"Arindam\"}";
}
It is also possible to let JAX-RS handle the mapping of a result to JSON. Let's write a second class for the response.
public class HelloResponse {
private String name;
// Constructor, Getter, Setter, ...
}
Change your JAX-RS method to return an instance of this class.
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public HelloResponse sayJSONHello2(UserConfig userConfig) {
System.out.println("got UserConfig: " + userConfig);
return new HelloResponse(userConfig.getName());
}

How to correctly handle this AJAX request that send an array to a Spring MVC controller method? Why it can't work?

I am pretty new in Spring MVC and I have the following problem trying to handle an AJAX request that send an array of int to a controller method.
So I have the following situation. I have this JQuery function:
// It is global and it is initiazilized by another function:
var checkedRowList = new Array();
// SOME OTHER CODE THAT INIZIALIZED THE checkedRowList array here
...............................................
...............................................
...............................................
$('#validaButton').click(function() {
alert("validazione");
alert("CHECKED ROWS: " + checkedRowList.length);
alert(checkedRowList[0]);
$.ajax({
type: "POST",
data: {'checkedRowList' : checkedRowList},
url: "validaProgetti"
}).done(function(response) {
alert("SUCCESS");
}).error(function(xhr) {
alert("ERROR");
manageError(xhr);
});
});
So the checkedRowList is correctly initizialized (I checked it) and I use the ajax() function to send it toward the validaProgetti resource using a POST request.
Then into a controller class I have this method that have to handle the previous request:
#RequestMapping(value = "validaProgetti", method=RequestMethod.POST)
public String validaProgetti(#RequestParam List<Integer> checkedRowList, Model model, HttpServletRequest request) {
System.out.println("Numero progetti da validare: " + checkedRowList);
return "blablabla";
}
As you can see it handle HTTP Post request toward the validaProgetti resource. And Inside it I have specify the RequestParam List checkedRowList to retry the array passed by the AJAX request.
But it don't work because when the AJAX request is performed it don't enter into the validaProgetti() method and it shown the alert("SUCCESS"); popup.
Why? What am I missing? How can I fix this situation?
as I see you missed two things.
The first one is that in the Spring Web MVC controller. You don't pass a RequestParam but RequestBody.
#RequestMapping(value = "validaProgetti", method=RequestMethod.POST)
public #ResponseBody String validaProgetti(#RequestBody List<Integer> checkedRowList) {
System.out.println("Numero progetti da validare: " + checkedRowList);
return "blablabla";
}
The second one is related with your Ajax request. You should send javascript array formatted as JSON. This is done via the function JSON.stringify(), which converts js value into json.
$('#validaButton').click(function() {
alert("validazione");
alert("CHECKED ROWS: " + checkedRowList.length);
alert(checkedRowList[0]);
$.ajax({
type: "POST",
data: JSON.stringify(checkedRowList),
url: "validaProgetti",
contentType:"application/json"
}).done(function(response) {
alert("SUCCESS");
}).error(function(xhr) {
alert("ERROR");
manageError(xhr);
});
});
Also you may change the request mapping when defining in java code. Since it is a relative path, it would be confusing in some cases.
#RequestMapping(value = "/validaProgetti", method=RequestMethod.POST)
public #ResponseBody String validaProgetti(#RequestBody List<Integer> checkedRowList) {
System.out.println("Numero progetti da validare: " + checkedRowList);
return "blablabla";
}

Restlet 1.1 Access Control Header Issue

I'm working on a restlet built on restlet 1.1.1
The issue I'm facing is setting the 'Access-Control-Allow-Origin' header to allow for cross domain requests. I've attempted a few things that didn't work.
Method one, put the header in the acceptRepresentation function:
#Override
public void acceptRepresentation( Representation resetEntity ) {
Form headers = (Form)getResponse().getAttributes().get("org.restlet.http.headers");
if (headers == null) {
headers = new Form();
getResponse().getAttributes().put("org.restlet.http.headers", headers);
}
headers.add("Access-Control-Allow-Origin","https://origin.server.edu");
//other code here for actual resource logic...
}
This didn't work. I still received errors when attempting to send a request using JQuery as such:
jQuery.ajax({
type: "POST",
contentType: "application/json",
url: "https://test.servername.edu/cas/cas-rest-api/reset/",
data: JSON.stringify("{\"uname\" : \"someone\", \"attr\":\"dataElement\" }"),
dataType: "json",
crossDomain: true
})
.done(function(data){
console.log("Success");
alert(data);
})
.fail(function(data){
console.log("failure");
console.log(data);
alert(data);
});
This didn't work. So I noticed an init function in the resource class. I figured I'd attempt putting my code there to see if this would change the situation.
#Override
public void init(Context context, Request request, Response response ){
Form headers = (Form)response.getAttributes().get("org.restlet.http.headers");
if (headers == null) {
headers = new Form();
response.getAttributes().put("org.restlet.http.headers", headers);
}
headers.add("Access-Control-Allow-Origin","https://origin.server.edu");
super.init(context, request, response);
}
Nope. Didn't work either. What am I missing here? Where do I set this header?
Thanks for your replies. After some analysis of the problem it turned out that I needed to configure Spring to allow option requests for my restlet in the web.xml file as shown below:
<servlet>
<servlet-name>ccrest</servlet-name>
<servlet-class>com.noelios.restlet.ext.spring.RestletFrameworkServlet</servlet-class>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

Categories