Stream ajax/xhr content into page while loading - java

Is there a way to "stream" content into a page while the XHR/AJAX call is loading? I have setup a REST based Java servlet (Restlet), using JSP for templating, and am using JavaScript to generate all the content via Dojo XHR calls to the RESTlet. The downside to this is while I'm waiting for page elements to finish loading asynchronously, they do not display. Not a problem locally, but when SSH'd in even 60 KB can take a bit of time to dynamically load if I'm in a bad 3G area, less some JSON fetches are 1-6 MB in size.
And yes I realize JSON has no order guarantee.
I would like to render the content as it's downloaded, instead of waiting for the content to complete the asynchronous fetch and then call function to render it after the xhr request "on load".
Example:
function getFinanceData() {
aniPreload("on");
var thePostData = "doWhat=getFinanceData";
var xhArgs = {
preventCache: true,
url: getResource("Finance"),
postData: thePostData,
handleAs: "json",
timeout: timeOutMilli,
load: function (data) {
putAssets(
data.qMerged[0],
data.bGames,
data.books,
data.dTools,
data.licenses,
data.assets
);
naviButtonListener();
aniPreload("off");
},
error: function (data, iostatus) {
aniPreload("off");
window.alert("xhrGet for FinanceData FAIL!, STATUS: " + iostatus.xhr.status + " (" + data + ")");
}
};
dojo.xhrPost(xhArgs);
}
Instead of load: function(data) { } I would like something like while loading function stream.

Your question is a bit jumbled, but... If 60K is taking a noticeable amount of time, you will have to live with that. For big transfers, where you want to see the beginning of the transfer while the rest completes, break the big request into smaller ones.
Update: I didn't mention this before, because would involve a lot of refactoring. But, I believe you could use WebSocket to achieve the streaming aspect. I didn't mention it before, however, because I'm not sure how streaming a long JSON is going to really help...

Related

jquery/angular scheduler implementation

I have a chat application written on jquery. When user sends a message, this message is being sent to java REST endpoint. But I also want to listen for response. I think it would be good to listen other REST endpoint every second, because I have no idea how to implement it like in Facebook. So if there new message, get them and show. How to do that in jquery?
There are couple of solutions for that, but I'd suggest you do not create chat application using REST. If you want pure JS think about firebase from google (it will be realtime)/meteor or definitely using Websockets (you'll need a websocket server and you can use authobahnjs to subscribe to that server).
I do realize it's solution that's more complicated than REST, but if you ask me and probably your customers REST is really not the best choice for chat/realtime applications...
Just think of situation where you will have lots of users online and each of them will not only be sending a lot of queries (if they write fast) but as well checking for response every second. Now think if something goes wrong on the network what will happen with your server... you'll get tons of 'hanging' connections etc.
btw. ppl who tried it (like me in past) will tell you the same, no chats with polling for messages over REST! ;)
JQuery way...
Ok, just watch out for defining multiple events on the same element (that’s classic one when working with Jquery), here’s a function that should do what you want (its a post, but you can adapt it):
var interval = 1000; // 1000 = 1 second, 3000 = 3 seconds
function doAjax() {
$.ajax({
type: 'POST',
url: 'chatController.php',
data: {action: 'getMessagesForUser', user: {user: 'data'}},
dataType: 'json',
success: function (data) {
//do something with results
},
complete: function (data) {
// Schedule the next
setTimeout(doAjax, interval);
}
});
}
setTimeout(doAjax, interval);
You could also introduce some variable that would make sure you're not making another request before the previous one has completed etc.

Spring MVC, best practice how to often polling server

Im working on web application using the following stack of technologies: Spring, Hibernate, JSP. I have a task to make one of user social element - messages. As standard of implementation message system i take facebook system. On of the problem i faced is a polling server every 1-5 seconds (what period i have to take?) to retrieve an information about unread messages. Also i want to polling server to retrieve new messages at conversation page (like a chat). What i did:
Example code of get count unread messages.
Server side:
#RequestMapping(value = "/getCountUserUnreadMessages", method = RequestMethod.POST)
public #ResponseBody Callable<Integer> getCountUserUnreadMessages(#ActiveUser final SmartUserDetails smartUserDetails) {
// TODO add additional security checks using username and active user
return new Callable<Integer>() {
#Override
public Integer call() throws Exception {
Integer countUserUnreadMessages = messageService.findCountUserUnreadMessages(smartUserDetails.getSmartUser());
while (countUserUnreadMessages == 0) {
Thread.sleep(1000);
countUserUnreadMessages = messageService.findCountUserUnreadMessages(smartUserDetails.getSmartUser());
}
return countUserUnreadMessages;
}
};
}
Client side:
(function poll(){
setTimeout(function () {
$.ajax({
type: "post",
url: "/messages/getCountUserUnreadMessages",
cache: false,
success: function (response) {
$("#countUnreadMessages").text(response);
}, dataType: "json", complete: poll, timeout: 1000 });
}, 3000);
})();
So client send a request to retrieve count unread messages every second with a timeout in 3 seconds (is it good decision?).
But i think that is the worst callable code ever :-P
Tell me how to do better? What technique use?
Additional information:
Yeah, i supposed that it would be highload, many users service in the Internet.
Try Spring 4 WebSocket support:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html
WebSockets support full duplex communication over a dedicated TCP connection that you establish over HTTP.
If you are expecting this application to have to scale at all I would make that timing interval more like every 30 - 90 seconds. Otherwise you are basically going to be designing your own built in DOS attack on your self.
You might look into Spring Sockets. It sounds like it's long polling option might work better for you.

Can Java Play framework store more than 100KB of a request in memory without writing to disk

I'm working on a throughput-intensive application, and in trying to identify the bottlenecks, I found that writing the request body to disk and then reading it back in when the entire request is received is a pretty slow operation.
My sending side will send me data up to 512KB in one HTTP POST and that can't be changed, so I'm looking for ways of handling it better on the server. In debugger I see, that Play uses RawBuffer class to manage incoming data and that class has memoryThreshold field, which is currently set for 100KB. Does anyone know of a way to programmatically or via a configuration file to change this default to be 512KB?
Update:
Things I've tried with no success:
Entering "parsers.text.maxLength=512K" in the application.conf file.
Just for kicks and giggles "parsers.raw.maxLength=512K" and "parsers.raw.memoryThreshold=512K" in application.conf
Adding "#BodyParser.Of( value = BodyParser.Raw.class, maxLength = 512 * 1024 )" annotation to my action method.
All three application.conf property names above with "512288" instead of "512K"
If I look at the code I read
lazy val DEFAULT_MAX_TEXT_LENGTH: Int = Play.maybeApplication.flatMap { app =>
app.configuration.getBytes("parsers.text.maxLength").map(_.toInt)
}.getOrElse(1024 * 100)
which makes me think that the parsers.text.maxLength property is the one you look for.

Long polling freezes browser and block other ajax request

I am trying to implement long polling in my Spring-MVC Web App but it freezes my browser and other request after 4-5 continues AJAX requests.I have no clue whats goin on here is my relevant code.
The controller method:(Server Side):-
#Asynchronous
#RequestMapping("/notify")
public #ResponseBody
Events notifyEvent(HttpServletRequest request) {
Events events = null;
try {
events = (Events) request.getSession(false).getServletContext().getAttribute("events");
System.out.println("Request Came from" + ((com.hcdc.coedp.safe.domain.User) request.getSession(false).getAttribute(Constants.KEY_LOGGED_IN_USER)).getLoginId());
if (!events.getTypeOfEvents().isEmpty()) {
System.out.println("Removing older entries");
events.getTypeOfEvents().clear();
}
while (!events.isHappend()) {
//Waiting for event to happen.
}
events = Events.getInstance();
events.setHappend(false);
request.getSession(false).getServletContext().setAttribute("events", events);
}catch (Exception e) {
e.printStackTrace();
}
return events;
}
The long-polling script(Client Side):-
$(document).ready(function() {
$.ajaxSetup({
async:true//set a global ajax requests as asynchronus
});
alert('Handler for .onload() called.');
waitForMsg();
});
function waitForMsg(){
xhr= $.ajax({
type: "POST",
url: '<%=request.getContextPath()%>/notification/notify',
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:50000, /* Timeout in ms */
global:false,
success: function(data){ /* called when request to notifier completes */
/* Doing smthing with response **/
setTimeout(
waitForMsg, /* Request next message */
1000 /* ..after 1 seconds */
);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
addmsg("error", textStatus + " (" + errorThrown + ")");
setTimeout(
waitForMsg, /* Try again after.. */
15000); /* milliseconds (15seconds) */
}
});
};
UPDATE:
function updateFeed(event, data) {
var f=eval(data);
alert(f.typeOfEvents.length);
}
function catchAll(event, data, type) {
console.log(data);
alert("error");
console.log(type);
}
$.comet.connect('<%=request.getContextPath()%>/notification/notify');
$(document).bind('feed.comet', updateFeed);
$(document).bind('.comet', catchAll);
Neither alert box pops up..:(
Seems like you experienced the session file lock
For PHP
Use session_write_close() when you don't need session value
It seems you have an empty while loop in your browser code.. this is a very CPU instensive way to wait for an event.
If no events happen the client will kill the request after your desired timeout of 50 seconds. But I'm not sure if the server thread is killed too, or if it "whiles" on forever (unless there is an event). The next request will start a second server thread that hangs in the while loop too then. Maybe the amount of empty while loops is an overkill for the server, so that it stops accepting any more requests. So after some requests (that each triggered an endless server thread) the client waits forever on a new request.. because it can't be handled by the server.
ps: on success you commented to wait 1 second, but set the timeout to 10000 (10 seconds)
I've met similar problem, my browser was stucked somehow with AJAX requests. Hint: instead using waitForMsg() directly, try setTimeout("waitForMsg()",10).
FYI, here is a project that might help you: https://github.com/SeanOC/jquery.comet
In general, I would search for JavaScript comet APIs that can support web sockets if available on client / server with graceful fallback to long polling. The API should handle all the gory details, allowing you to focus on the application.
Here's a link to an old dojo article on the topic: http://dojotoolkit.org/features/1.6/dojo-websocket
Good luck.
You can try to rewrite the behaviour using jQuery deferred:
function setShortTimeout() {
setTimeout(waitForMsg, 1000);
}
function setLongTimeout() {
setTimeout(waitForMsg, 15000);
}
$(document).ready(function() {
$.ajaxSetup({
async:true//set a global ajax requests as asynchronus
});
alert('Handler for .onload() called.');
$.when(waitForMsg())
.done(successHandler, setShortTimeout)
.fail(errorHandler, setLongTimeout);
});
function waitForMsg(){
return $.ajax({
type: "POST",
url: '<%=request.getContextPath()%>/notification/notify',
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:50000, /* Timeout in ms */
global:false
});
};
errorHandler and successHandler will be your success: and error: callbacks, which I omitted for clarity, with their setTimeout part removed (since it is now part of the deferred.done() and .fail() callbacks).
Let me know if it works.
I am a PHP developer but I met your problem and it could be the same behaviour. So I give you my 2 cents and hope it'll help you.
The line that does make me suspect a problem is :
events = (Events) request.getSession(false).getServletContext().getAttribute("events");
In PHP, sessions are stored in files, and if we are long-polling on a php script while the session is open, we meet a race condition problem.
The principle is quite simple :
When a request opens the session, file is locked until the session
is closed.
If other requests comes to the server, they will be locked until the
session is released from the previous request.
In a case of long polling, if the session is opened and not closed just after getting information (at least, just before waiting for events), all requests are just locked, you can't go anywhere else in the website if you're using sessions on other pages. Even if you open a new tab, because for one browser there is only one session, you're locked.
It may be this:
xhr= $.ajax({ (...)
in your waitForMsg function.
Try
var xhr = (...)
It may be that you are declaring xhr in the global object, thus making it impossible to respond to two different requests.

Setting up AJAX progress bar

Ok im new to AJAX. Kind of know about the lifecycle of a request, IE uses ActiveXObject stuff like that.
However now im faced with a real world problem. I have a servlet running in the background that performs a number of tasks and i would like to display a progress bar to show where the process is up to and to also show that something is actually happening.
So far in the server side i can calculate the number of processes that will take place before they begin, and easily enough add a counter to increment after each process completes - therefore enabling me to find the percentage i wish to show.
In terms of where i should output the data gathered from incrementing etc i'm not sure so far it is dormant as 2 integers in the processing java class.
Any help would be much appreciated.
So far i've taken a look at this and i guess thats kind of what im aiming for.
Cheers.
Basically, you'd like to store a reference to the task and inherently also its progress in the HTTP session (or in the Servlet context if it concerns an application wide task). This way you must be able to retrieve information about it on every HTTP request.
In JavaScript, you can use setTimeout() or setInterval() to execute a function after a certain timeout or at certain intervals. You can use this to repeatedly fire Ajax requests to request current status of the progress. Once the status is retrieved, e.g. in flavor of an integer with a max value of 100 (the percentage), just update some div representing a progressbar and/or the percentage text accordingly in the HTML DOM tree.
jQuery is very helpful in firing ajaxical requests and traversing/manipulating the HTML DOM tree like that. It minimizes the code verbosity and crossbrowser compatibility headaches.
Imagine that the doGet() of the servlet look like this:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String processId = "longProcess_" + request.getParameter("processId");
LongProcess longProcess = (LongProcess) request.getSession().getAttribute(processId);
int progress = longProcess.getProgress();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(String.valueOf(progress));
}
Then you can use it like follows:
function checkProgress() {
$.getJSON('progressServlet?processId=someid', function(progress) {
$('#progress').text(progress + "%");
$('#progress .bar').width(progress);
if (parseInt(progress) < 100) {
setTimeout(checkProgress, 1000); // Checks again after one second.
}
});
}

Categories

Resources