File upload progress

View: New views
20 Messages — Rating Filter:   Alert me  
< Prev | 1 - 2 - 3 | Next >

File upload progress

by Lance Java :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I've been doing a fair bit of work on out of the box dwr support for file upload progress and cancel but wanted to run the new API past the user's list to get some feedback.

The basic approach is this:

<javascript>
dwr.engine.setUploadProgressPollInterval(...);
Remote.uploadFile(
   dwr.util.byId("myFile"),
   callback: ...,
   progressCallback: function(percentageComplete) {
      updateSomeWidget(percentageComplete);
   },
   id: "myUpload" // this allows a developer to provide a handle for the upload, dwr generates it's own invocationId to use internally
);

dwr.engine.cancelUpload("myUpload");
</javascript>

engine.js generates an invocationId which is passed to the server which can be used to cancel an upload or poll it's current progress.

On the serverside there is a (pluggable) UploadManager with the following interface:

public interface UploadManager {
    public void updateProgress(String invocationId, long bytesRead, long contentLength, int currentItemIndex);
    public double getPercentageComplete(String invocationId);
    public void cancelUpload(String invocationId);
}

I have implemented 2 upload managers. 1 stores on the session (similar to the current approach). Another (default) stores to a local map.

There is also a (pluggable) FileUpload (default CommonsFileUpload) that is capable of parsing a multipart request and informing the UploadManager of the current progress for the invocationId.

So... my main questions to the group are:

1. How many people use the current file upload progress implementation (storing on session)
2. Does anyone currently support cancel of a file upload
3. Do we agree on the UploadManager approach (you'll need a good argument here!)
4. Does anyone have arguments for better naming conventions
  a) dwr.engine.setUploadProgressPollInterval(...)
  b) progressCallback: function(percentageComplete) { ... }
  c) id: "myUpload"
  d) dwr.engine.cancelUpload("myUpload");
  e) invocationId
5. Any other suggestions / improvements?

Cheers,
Lance.




Re: File upload progress

by XMaNIaC :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Some general ideas I have in mind (in addition to Lance work):

 * By default we should create a null progress listener
 * Add a delay param to include server side latency (useful for testing)
 * Include the poll interval in the arguments (if able)
 * Configure a timeout
 * Configure a max upload size

Regards

On Wed, Jun 3, 2009 at 4:41 PM, Lance Java <lance.java@...> wrote:
I've been doing a fair bit of work on out of the box dwr support for file upload progress and cancel but wanted to run the new API past the user's list to get some feedback.

The basic approach is this:

<javascript>
dwr.engine.setUploadProgressPollInterval(...);
Remote.uploadFile(
   dwr.util.byId("myFile"),
   callback: ...,
   progressCallback: function(percentageComplete) {
      updateSomeWidget(percentageComplete);
   },
   id: "myUpload" // this allows a developer to provide a handle for the upload, dwr generates it's own invocationId to use internally
);

dwr.engine.cancelUpload("myUpload");
</javascript>

engine.js generates an invocationId which is passed to the server which can be used to cancel an upload or poll it's current progress.

On the serverside there is a (pluggable) UploadManager with the following interface:

public interface UploadManager {
    public void updateProgress(String invocationId, long bytesRead, long contentLength, int currentItemIndex);
    public double getPercentageComplete(String invocationId);
    public void cancelUpload(String invocationId);
}

I have implemented 2 upload managers. 1 stores on the session (similar to the current approach). Another (default) stores to a local map.

There is also a (pluggable) FileUpload (default CommonsFileUpload) that is capable of parsing a multipart request and informing the UploadManager of the current progress for the invocationId.

So... my main questions to the group are:

1. How many people use the current file upload progress implementation (storing on session)
2. Does anyone currently support cancel of a file upload
3. Do we agree on the UploadManager approach (you'll need a good argument here!)
4. Does anyone have arguments for better naming conventions
  a) dwr.engine.setUploadProgressPollInterval(...)
  b) progressCallback: function(percentageComplete) { ... }
  c) id: "myUpload"
  d) dwr.engine.cancelUpload("myUpload");
  e) invocationId
5. Any other suggestions / improvements?

Cheers,
Lance.





RE: File upload progress

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Lance wrote: 
 I've been doing a fair bit of work on out of the box dwr support for file upload progress and cancel but wanted to run the new API past the user's list to get some feedback.
That's great!
The basic approach is this:

<javascript>
dwr.engine.setUploadProgressPollInterval(...);
Remote.uploadFile(
   dwr.util.byId("myFile"),
   callback: ...,
   progressCallback: function(percentageComplete) {
      updateSomeWidget(percentageComplete);
   },
   id: "myUpload" // this allows a developer to provide a handle for the upload, dwr generates it's own invocationId to use internally
);
I guess you forgot the object brackets for the options object in your example? With them it would look like this I think:
Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(percentageComplete) {
            updateSomeWidget(percentageComplete);
        },
        id: "myUpload"
    }
);
So, to my comments:
 
1) Settings
I can see two new configuration options in the example:
  • progressCallback
  • uploadProgressPollInterval
I think they should have a consistent naming and both should be available to set in the options object. We might have global defaults for these options (as you suggest with dwr.engine.setUploadProgressPollInterval) but we could also do without that?
dwr.engine.cancelUpload("myUpload");
</javascript>

engine.js generates an invocationId which is passed to the server which can be used to cancel an upload or poll it's current progress.
2) Generic progress and cancellation
As you mentioned in an earlier mail, it could be interesting to provide a generic progress/cancellation mechanism for all calls, not just for file uploads. I then think it would be natural to return an object from any async call following the Deferred/Future pattern. This object could be used for asking about progress, completion status or to trigger cancellation, and would replace (but possibly contain) the invocationId in your example.
If providing progress for all kinds of requests, then we can not depend on always getting a percentage to the progress callback, as we typically don't know the size of outbound data. The parameters could instead be designed this way:
function(transferredBytes, totalBytes)
and the totalBytes would only be set in the cases when we do have that information (and could easily be converted to a percentage). When totalBytes is undefined, a progress dialog could still show the running transferredBytes count.
 
3) Invocation id
After thinking a fair bit on this I'm a little worried about us taking the responsibility to create a unique id in client code. Joe had the same dilemma for the script session ids and decided to go with server-side generation. Also, we already have the scriptSessionId that is such a unique number that identifies a loaded page in the browser.
The invocationId needs to uniquely identify each call to the server and basing off the scriptSessionId we would just have to add a sequential call index number that we can keep locally in the client layer.
What I just recommended doesn't work if we disable script sessions, and this is a configuration I am personally interested in. Though, if disabling script sessions I think it is ok to require the user code to invent a good enough invocationId. So, by default I think we should use the scriptSessionId algorithm, and then allow it to be overridden in the options object.
 
Summing these suggestions up, this is how I would expect them to work:
 
Specifying no progress callback means no progress handling will be done. The returned Deferred object allows us to manually check progress or cancel upload:
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...
    }
);
dwr.engine.getProgress(deferredInvocation) // sends progress check request
dwr.engine.isCompleted(deferredInvocation) // internal flag, no request needed
dwr.engine.cancel(deferredInvocation)
[Some more thought could be put into these method names]
Specifying a progress callback means progress handling will be active (in this case with scriptSessionId algorithm):
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(...) {},
        progressInterval: 500 // msec
    }
);
And finally, also specifying an invocationId means that we override the scriptSessionId algorithm with our own:
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(...) {},
        progressInterval: 500, // msec
        invocationId: "my Internet-wide unique string"
    }
);
On the serverside there is a (pluggable) UploadManager with the following interface:

public interface UploadManager {
    public void updateProgress(String invocationId, long bytesRead, long contentLength, int currentItemIndex);
    public double getPercentageComplete(String invocationId);
    public void cancelUpload(String invocationId);
}
Nice.
When/if going into a generic progress/cancellation feature, there would also be functionality like this in DWR's normal communication stack and the progress/cancellation calls would at some point branch to either be handled by the file uploader or the DWR stack. I guess we would then like to have them implement the same interface so maybe this interface would look a little different, I'm not sure.
I have implemented 2 upload managers. 1 stores on the session (similar to the current approach).  
If the scriptSessionId suggestion above works out, then I guess the default upload manager should store progress on the script session. A session-oriented upload manager would only be needed if it is desirable to track the progress from a different page than the one doing the upload, but then some kind of "list current uploads on session" function would also be needed.
Another (default) stores to a local map. 
I'm not sure what you mean with "local map"?
There is also a (pluggable) FileUpload (default CommonsFileUpload) that is capable of parsing a multipart request and informing the UploadManager of the current progress for the invocationId.
Nice too :-)
So... my main questions to the group are:

1. How many people use the current file upload progress implementation (storing on session)
2. Does anyone currently support cancel of a file upload
3. Do we agree on the UploadManager approach (you'll need a good argument here!) 
Interface could be affected by "generic support" choice discussed above.
 4. Does anyone have arguments for better naming conventions
  a) dwr.engine.setUploadProgressPollInterval(...)
  b) progressCallback: function(percentageComplete) { ... }
  c) id: "myUpload" 
Replacing id with Deferred return value.
  d) dwr.engine.cancelUpload("myUpload");
  e) invocationId
5. Any other suggestions / improvements? 
I remember from a previous discussion that it was suggested that progress could be delivered by Reverse Ajax, if active on the page. I'm not sure how much that would complicate things.
 
Best regards
Mike

RE: File upload progress

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Mike Wilson wrote:

3) Invocation id
... 
The invocationId needs to uniquely identify each call to the server and basing off the scriptSessionId we would just have to add a sequential call index number that we can keep locally in the client layer. 
I should mention that we already have this sequential number as well; the batch id. So, the combination of scriptSessionId and batchId uniquely identifies every call to the server, including file uploads.
 
Best regards
Mike

Re: File upload progress

by Lance Java :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Comments below

2009/6/8 Mike Wilson <mikewse@...>
Mike Wilson wrote:

3) Invocation id
... 
The invocationId needs to uniquely identify each call to the server and basing off the scriptSessionId we would just have to add a sequential call index number that we can keep locally in the client layer. 
I should mention that we already have this sequential number as well; the batch id. So, the combination of scriptSessionId and batchId uniquely identifies every call to the server, including file uploads.

My original invocationId used scriptSessionId + batchId but I moved to a random number to support a DWR mode without script sessions. Perhaps I could check if scriptSessionId is null and only use the random number in this case.
 
 
Best regards
Mike


Re: File upload progress

by Lance Java :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



2009/6/7 Mike Wilson <mikewse@...>
Lance wrote: 
 I've been doing a fair bit of work on out of the box dwr support for file upload progress and cancel but wanted to run the new API past the user's list to get some feedback.
That's great!
The basic approach is this:

<javascript>
dwr.engine.setUploadProgressPollInterval(...);
Remote.uploadFile(
   dwr.util.byId("myFile"),
   callback: ...,
   progressCallback: function(percentageComplete) {
      updateSomeWidget(percentageComplete);
   },
   id: "myUpload" // this allows a developer to provide a handle for the upload, dwr generates it's own invocationId to use internally
);
I guess you forgot the object brackets for the options object in your example? With them it would look like this I think:
Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(percentageComplete) {
            updateSomeWidget(percentageComplete);
        },
        id: "myUpload"
    }
);
Correct. 
So, to my comments:
 
1) Settings
I can see two new configuration options in the example:
  • progressCallback
  • uploadProgressPollInterval
I think they should have a consistent naming and both should be available to set in the options object. We might have global defaults for these options (as you suggest with dwr.engine.setUploadProgressPollInterval) but we could also do without that?
dwr.engine.cancelUpload("myUpload");
</javascript>

engine.js generates an invocationId which is passed to the server which can be used to cancel an upload or poll it's current progress.
2) Generic progress and cancellation
As you mentioned in an earlier mail, it could be interesting to provide a generic progress/cancellation mechanism for all calls, not just for file uploads. I then think it would be natural to return an object from any async call following the Deferred/Future pattern. This object could be used for asking about progress, completion status or to trigger cancellation, and would replace (but possibly contain) the invocationId in your example.
If providing progress for all kinds of requests, then we can not depend on always getting a percentage to the progress callback, as we typically don't know the size of outbound data. The parameters could instead be designed this way:
function(transferredBytes, totalBytes)
and the totalBytes would only be set in the cases when we do have that information (and could easily be converted to a percentage). When totalBytes is undefined, a progress dialog could still show the running transferredBytes count.

Hmm... this locks us into a file upload now rather than a more generic process percentage. I'm not 100% on this but could be talked into it.
 
 
3) Invocation id
After thinking a fair bit on this I'm a little worried about us taking the responsibility to create a unique id in client code. Joe had the same dilemma for the script session ids and decided to go with server-side generation. Also, we already have the scriptSessionId that is such a unique number that identifies a loaded page in the browser.
The invocationId needs to uniquely identify each call to the server and basing off the scriptSessionId we would just have to add a sequential call index number that we can keep locally in the client layer.
What I just recommended doesn't work if we disable script sessions, and this is a configuration I am personally interested in. Though, if disabling script sessions I think it is ok to require the user code to invent a good enough invocationId. So, by default I think we should use the scriptSessionId algorithm, and then allow it to be overridden in the options object.
 
Summing these suggestions up, this is how I would expect them to work:
 
Specifying no progress callback means no progress handling will be done. The returned Deferred object allows us to manually check progress or cancel upload:
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...
    }
);
dwr.engine.getProgress(deferredInvocation) // sends progress check request
dwr.engine.isCompleted(deferredInvocation) // internal flag, no request needed
dwr.engine.cancel(deferredInvocation)
[Some more thought could be put into these method names]
Specifying a progress callback means progress handling will be active (in this case with scriptSessionId algorithm):
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(...) {},
        progressInterval: 500 // msec
    }
);
And finally, also specifying an invocationId means that we override the scriptSessionId algorithm with our own:
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(...) {},
        progressInterval: 500, // msec
        invocationId: "my Internet-wide unique string"
    }
);

This works for me... I originally considered returning an object from a DWR call but wasn't sold on the idea since in sync mode {async: false} DWR returns the remote response. I wasn't sure of the implications here. This will obviously require a bit more work to implement this approach.
 
On the serverside there is a (pluggable) UploadManager with the following interface:

public interface UploadManager {
    public void updateProgress(String invocationId, long bytesRead, long contentLength, int currentItemIndex);
    public double getPercentageComplete(String invocationId);
    public void cancelUpload(String invocationId);
}
Nice.
When/if going into a generic progress/cancellation feature, there would also be functionality like this in DWR's normal communication stack and the progress/cancellation calls would at some point branch to either be handled by the file uploader or the DWR stack. I guess we would then like to have them implement the same interface so maybe this interface would look a little different, I'm not sure.

This interface can change in the future if we support cancel / progress of other long-running tasks. Perhaps a comment in the javadoc would help here.
I have implemented 2 upload managers. 1 stores on the session (similar to the current approach).  
If the scriptSessionId suggestion above works out, then I guess the default upload manager should store progress on the script session. A session-oriented upload manager would only be needed if it is desirable to track the progress from a different page than the one doing the upload, but then some kind of "list current uploads on session" function would also be needed.

It's trivial to plug in a ScriptSessionUploadManager 
Another (default) stores to a local map. 
I'm not sure what you mean with "local map"?

I just mean a member variable on the DefaultUploadManager singleton 
There is also a (pluggable) FileUpload (default CommonsFileUpload) that is capable of parsing a multipart request and informing the UploadManager of the current progress for the invocationId.
Nice too :-)
So... my main questions to the group are:

1. How many people use the current file upload progress implementation (storing on session)
2. Does anyone currently support cancel of a file upload
3. Do we agree on the UploadManager approach (you'll need a good argument here!) 
Interface could be affected by "generic support" choice discussed above.
 4. Does anyone have arguments for better naming conventions
  a) dwr.engine.setUploadProgressPollInterval(...)
  b) progressCallback: function(percentageComplete) { ... }
  c) id: "myUpload" 
Replacing id with Deferred return value.
  d) dwr.engine.cancelUpload("myUpload");
  e) invocationId
5. Any other suggestions / improvements? 
I remember from a previous discussion that it was suggested that progress could be delivered by Reverse Ajax, if active on the page. I'm not sure how much that would complicate things.

I think that reverse ajax polls are less frequent than what is required to update a progress widget. The two could be combined in the future but I'm not going to attempt this at this stage.
 
 
Best regards
Mike


RE: File upload progress

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Lance wrote:
2009/6/7 Mike Wilson <mikewse@...>
Lance wrote:  
dwr.engine.cancelUpload("myUpload");
</javascript>

engine.js generates an invocationId which is passed to the server which can be used to cancel an upload or poll it's current progress.
2) Generic progress and cancellation
As you mentioned in an earlier mail, it could be interesting to provide a generic progress/cancellation mechanism for all calls, not just for file uploads. I then think it would be natural to return an object from any async call following the Deferred/Future pattern. This object could be used for asking about progress, completion status or to trigger cancellation, and would replace (but possibly contain) the invocationId in your example.
If providing progress for all kinds of requests, then we can not depend on always getting a percentage to the progress callback, as we typically don't know the size of outbound data. The parameters could instead be designed this way:
function(transferredBytes, totalBytes)
and the totalBytes would only be set in the cases when we do have that information (and could easily be converted to a percentage). When totalBytes is undefined, a progress dialog could still show the running transferredBytes count.

Hmm... this locks us into a file upload now rather than a more generic process percentage. I'm not 100% on this but could be talked into it. 
My point was actually the opposite, ie not to lock us into file upload ;-).
Normally, it is only at upload (file or data) that we know the total number of bytes we are going to send and can thus calculate the percentage. If we want to use generic progress handling for large sets of outbound data ("download") then we normally don't know the total size at it is processed in a streaming fashion. This makes the percentage impossible to calculate for this case, and therefore I suggested the "transferred byte count so far" to be used in the progress callback.
 
Also, I believe that it could be interesting for the progress indicator to be able, at will, to show the byte count and not just the percentage. Percentages can easily be derived from the bytes if the total is available.
3) Invocation id
After thinking a fair bit on this I'm a little worried about us taking the responsibility to create a unique id in client code. Joe had the same dilemma for the script session ids and decided to go with server-side generation. Also, we already have the scriptSessionId that is such a unique number that identifies a loaded page in the browser.
The invocationId needs to uniquely identify each call to the server and basing off the scriptSessionId we would just have to add a sequential call index number that we can keep locally in the client layer.
What I just recommended doesn't work if we disable script sessions, and this is a configuration I am personally interested in. Though, if disabling script sessions I think it is ok to require the user code to invent a good enough invocationId. So, by default I think we should use the scriptSessionId algorithm, and then allow it to be overridden in the options object.
Adding my own followup:
I should mention that we already have this sequential number as well; the batch id. So, the combination of scriptSessionId and batchId uniquely identifies every call to the server, including file uploads.

My original invocationId used scriptSessionId + batchId but I moved to a random number to support a DWR mode without script sessions.  
I believe it might have been me asking you not to depend on script sessions, and I think it is good to support other configurations.
Perhaps I could check if scriptSessionId is null and only use the random number in this case.
As I wrote earlier I think we should avoid trying to generate a unique id in the DWR client layer, and leave this to the application code when the default script session based implementation is not used. With this I mean we should not have any random number generation at all in our code, not even as a fallback.
 
About a potentially unset scriptSessionId (because of a fresh page), I think the following behaviour could be appropriate:
 
Default upload:
Remote.uploadFile(dwr.util.byId("myFile"), {
    callback: ...,
    progressCallback:  ... 
});
 
Here the default ScriptSession-based incovationId is used, so the client layer needs to know the scriptSessionId before sending along the upload, as we would otherwise not know what invocationId to poll progress about.
Thus, if scriptSessionId has not yet been set we need to send a pre-flight call that retrieves this id (this is always done by the first call from a fresh page, f ex by reverse Ajax polls when using that mode). After the return of that request we can then start the real upload request.
Custom upload:
Remote.uploadFile(dwr.util.byId("myFile"), {
    callback: ...,
    progressCallback:  ...,
    invocationId: ...
});
 
Here a custom incovationId is used, so we already know what invocationId to poll for in the progress handling. No scriptSessionId or pre-flight call needed.
Summing these suggestions up, this is how I would expect them to work:
 
Specifying no progress callback means no progress handling will be done. The returned Deferred object allows us to manually check progress or cancel upload:
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...
    }
);
dwr.engine.getProgress(deferredInvocation) // sends progress check request
dwr.engine.isCompleted(deferredInvocation) // internal flag, no request needed
dwr.engine.cancel(deferredInvocation)
[Some more thought could be put into these method names]
Specifying a progress callback means progress handling will be active (in this case with scriptSessionId algorithm):
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(...) {},
        progressInterval: 500 // msec
    }
);
And finally, also specifying an invocationId means that we override the scriptSessionId algorithm with our own:
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(...) {},
        progressInterval: 500, // msec
        invocationId: "my Internet-wide unique string"
    }
);

This works for me... I originally considered returning an object from a DWR call but wasn't sold on the idea since in sync mode {async: false} DWR returns the remote response. I wasn't sure of the implications here. This will obviously require a bit more work to implement this approach.
Yes, I thought about the sync thing as well. Conceptually though, when you use a sync call you have already said that you want to use JavaScript's single thread to wait for the operation to complete before doing anything else, including updating progress (most browsers also freeze the UI during a sync call).
It is only when you do an async call that you could normally let your single JavaScript thread do other work during the upload, like updating progress.
So I think it is quite "correct", and follows standard patterns, to return a handle to the running operation as a return value only from an async call, and not do this for sync calls (it is natural for sync calls to return the resulting value).
 
Also, normally you cannot use sync mode for file uploads as sync requires XHR (though Firefox has added file upload capabilities that can be used by XHR). 
If the scriptSessionId suggestion above works out, then I guess the default upload manager should store progress on the script session.

It's trivial to plug in a ScriptSessionUploadManager  
Yes, should be.
Another (default) stores to a local map. 
I'm not sure what you mean with "local map"?

I just mean a member variable on the DefaultUploadManager singleton  
Ah, right, the application global version. This is the hardest one to make secure (user code-generated invocationIds must be unique over all current users of the site) so this should not be the default upload manager. 
I remember from a previous discussion that it was suggested that progress could be delivered by Reverse Ajax, if active on the page. I'm not sure how much that would complicate things.

I think that reverse ajax polls are less frequent than what is required to update a progress widget. The two could be combined in the future but I'm not going to attempt this at this stage. 
I think the goal in that previous discussion was to use reverse ajax in streaming mode so updates are transmitted immediately, but within the same request. Ie, a single poll and then pushing progress from the server into the poll request's response stream every 500ms or whatever has been set. This certainly doesn't have to be implemented now, but it would be good if you could take a quick look to see if it will be possible to add this feature within the current public APIs we are designing now.
 
Best regards
Mike

Re: File upload progress

by Lance Java :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



2009/6/9 Mike Wilson <mikewse@...>
Lance wrote:
2009/6/7 Mike Wilson <mikewse@...>
Lance wrote:  
dwr.engine.cancelUpload("myUpload");
</javascript>

engine.js generates an invocationId which is passed to the server which can be used to cancel an upload or poll it's current progress.
2) Generic progress and cancellation
As you mentioned in an earlier mail, it could be interesting to provide a generic progress/cancellation mechanism for all calls, not just for file uploads. I then think it would be natural to return an object from any async call following the Deferred/Future pattern. This object could be used for asking about progress, completion status or to trigger cancellation, and would replace (but possibly contain) the invocationId in your example.
If providing progress for all kinds of requests, then we can not depend on always getting a percentage to the progress callback, as we typically don't know the size of outbound data. The parameters could instead be designed this way:
function(transferredBytes, totalBytes)
and the totalBytes would only be set in the cases when we do have that information (and could easily be converted to a percentage). When totalBytes is undefined, a progress dialog could still show the running transferredBytes count.

Hmm... this locks us into a file upload now rather than a more generic process percentage. I'm not 100% on this but could be talked into it. 
My point was actually the opposite, ie not to lock us into file upload ;-).
Normally, it is only at upload (file or data) that we know the total number of bytes we are going to send and can thus calculate the percentage. If we want to use generic progress handling for large sets of outbound data ("download") then we normally don't know the total size at it is processed in a streaming fashion. This makes the percentage impossible to calculate for this case, and therefore I suggested the "transferred byte count so far" to be used in the progress callback.
 
Also, I believe that it could be interesting for the progress indicator to be able, at will, to show the byte count and not just the percentage. Percentages can easily be derived from the bytes if the total is available.

By generic I am talking about for all long running tasks, not necessarily involving bytes. I've seen a really good implementation of a progress indicator where processes were able to return strings stating which stage they were at. A progress manager would after a while collect the results of the same process and would be able to estimate the percentage complete on the current stage and previous results. It's not perfect but the progress widget moved quite steadily after it had collected a big enough survey. Food for thought anyway.

3) Invocation id
After thinking a fair bit on this I'm a little worried about us taking the responsibility to create a unique id in client code. Joe had the same dilemma for the script session ids and decided to go with server-side generation. Also, we already have the scriptSessionId that is such a unique number that identifies a loaded page in the browser.
The invocationId needs to uniquely identify each call to the server and basing off the scriptSessionId we would just have to add a sequential call index number that we can keep locally in the client layer.
What I just recommended doesn't work if we disable script sessions, and this is a configuration I am personally interested in. Though, if disabling script sessions I think it is ok to require the user code to invent a good enough invocationId. So, by default I think we should use the scriptSessionId algorithm, and then allow it to be overridden in the options object.
Adding my own followup:
I should mention that we already have this sequential number as well; the batch id. So, the combination of scriptSessionId and batchId uniquely identifies every call to the server, including file uploads.

My original invocationId used scriptSessionId + batchId but I moved to a random number to support a DWR mode without script sessions.  
I believe it might have been me asking you not to depend on script sessions, and I think it is good to support other configurations.
Perhaps I could check if scriptSessionId is null and only use the random number in this case.
As I wrote earlier I think we should avoid trying to generate a unique id in the DWR client layer, and leave this to the application code when the default script session based implementation is not used. With this I mean we should not have any random number generation at all in our code, not even as a fallback.
 
About a potentially unset scriptSessionId (because of a fresh page), I think the following behaviour could be appropriate:
 
Default upload:
Remote.uploadFile(dwr.util.byId("myFile"), 
{
    callback: ...,
    progressCallback:  ... 
});
 
Here the default ScriptSession-based incovationId is used, so the client layer needs to know the scriptSessionId before sending along the upload, as we would otherwise not know what invocationId to poll progress about.
Thus, if scriptSessionId has not yet been set we need to send a pre-flight call that retrieves this id (this is always done by the first call from a fresh page, f ex by reverse Ajax polls when using that mode). After the return of that request we can then start the real upload request.
Custom upload:
Remote.uploadFile(dwr.util.byId("myFile"), 
{
    callback: ...,
    progressCallback:  ...,
    invocationId: ...
});
 
Here a custom incovationId is used, so we already know what invocationId to poll for in the progress handling. No scriptSessionId or pre-flight call needed.
Summing these suggestions up, this is how I would expect them to work:
 
Specifying no progress callback means no progress handling will be done. The returned Deferred object allows us to manually check progress or cancel upload:
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...
    }
);
dwr.engine.getProgress(deferredInvocation) // sends progress check request
dwr.engine.isCompleted(deferredInvocation) // internal flag, no request needed
dwr.engine.cancel(deferredInvocation)
[Some more thought could be put into these method names]
Specifying a progress callback means progress handling will be active (in this case with scriptSessionId algorithm):
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(...) {},
        progressInterval: 500 // msec
    }
);
And finally, also specifying an invocationId means that we override the scriptSessionId algorithm with our own:
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(...) {},
        progressInterval: 500, // msec
        invocationId: "my Internet-wide unique string"
    }
);

This works for me... I originally considered returning an object from a DWR call but wasn't sold on the idea since in sync mode {async: false} DWR returns the remote response. I wasn't sure of the implications here. This will obviously require a bit more work to implement this approach.
Yes, I thought about the sync thing as well. Conceptually though, when you use a sync call you have already said that you want to use JavaScript's single thread to wait for the operation to complete before doing anything else, including updating progress (most browsers also freeze the UI during a sync call).
It is only when you do an async call that you could normally let your single JavaScript thread do other work during the upload, like updating progress.
So I think it is quite "correct", and follows standard patterns, to return a handle to the running operation as a return value only from an async call, and not do this for sync calls (it is natural for sync calls to return the resulting value).
 
Also, normally you cannot use sync mode for file uploads as sync requires XHR (though Firefox has added file upload capabilities that can be used by XHR). 
If the scriptSessionId suggestion above works out, then I guess the default upload manager should store progress on the script session.

It's trivial to plug in a ScriptSessionUploadManager  
Yes, should be.
Another (default) stores to a local map. 
I'm not sure what you mean with "local map"?

I just mean a member variable on the DefaultUploadManager singleton  
Ah, right, the application global version. This is the hardest one to make secure (user code-generated invocationIds must be unique over all current users of the site) so this should not be the default upload manager. 
I remember from a previous discussion that it was suggested that progress could be delivered by Reverse Ajax, if active on the page. I'm not sure how much that would complicate things.

I think that reverse ajax polls are less frequent than what is required to update a progress widget. The two could be combined in the future but I'm not going to attempt this at this stage. 
I think the goal in that previous discussion was to use reverse ajax in streaming mode so updates are transmitted immediately, but within the same request. Ie, a single poll and then pushing progress from the server into the poll request's response stream every 500ms or whatever has been set. This certainly doesn't have to be implemented now, but it would be good if you could take a quick look to see if it will be possible to add this feature within the current public APIs we are designing now.

I must say that my knowlege of how comet works is more theoretical than practical. Can you lead me towards some of the classes you'd like me to take a look at?
 
 
Best regards
Mike


Re: File upload progress

by XMaNIaC :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Tue, Jun 9, 2009 at 8:04 PM, Mike Wilson <mikewse@...> wrote:
Lance wrote:
2009/6/7 Mike Wilson <mikewse@...>
Lance wrote:  
dwr.engine.cancelUpload("myUpload");
</javascript>

engine.js generates an invocationId which is passed to the server which can be used to cancel an upload or poll it's current progress.
2) Generic progress and cancellation
As you mentioned in an earlier mail, it could be interesting to provide a generic progress/cancellation mechanism for all calls, not just for file uploads. I then think it would be natural to return an object from any async call following the Deferred/Future pattern. This object could be used for asking about progress, completion status or to trigger cancellation, and would replace (but possibly contain) the invocationId in your example.
If providing progress for all kinds of requests, then we can not depend on always getting a percentage to the progress callback, as we typically don't know the size of outbound data. The parameters could instead be designed this way:
function(transferredBytes, totalBytes)
and the totalBytes would only be set in the cases when we do have that information (and could easily be converted to a percentage). When totalBytes is undefined, a progress dialog could still show the running transferredBytes count.

Hmm... this locks us into a file upload now rather than a more generic process percentage. I'm not 100% on this but could be talked into it. 
My point was actually the opposite, ie not to lock us into file upload ;-).
Normally, it is only at upload (file or data) that we know the total number of bytes we are going to send and can thus calculate the percentage. If we want to use generic progress handling for large sets of outbound data ("download") then we normally don't know the total size at it is processed in a streaming fashion. This makes the percentage impossible to calculate for this case, and therefore I suggested the "transferred byte count so far" to be used in the progress callback.
 
Also, I believe that it could be interesting for the progress indicator to be able, at will, to show the byte count and not just the percentage. Percentages can easily be derived from the bytes if the total is available.
3) Invocation id
After thinking a fair bit on this I'm a little worried about us taking the responsibility to create a unique id in client code. Joe had the same dilemma for the script session ids and decided to go with server-side generation. Also, we already have the scriptSessionId that is such a unique number that identifies a loaded page in the browser.
The invocationId needs to uniquely identify each call to the server and basing off the scriptSessionId we would just have to add a sequential call index number that we can keep locally in the client layer.
What I just recommended doesn't work if we disable script sessions, and this is a configuration I am personally interested in. Though, if disabling script sessions I think it is ok to require the user code to invent a good enough invocationId. So, by default I think we should use the scriptSessionId algorithm, and then allow it to be overridden in the options object.
Adding my own followup:
I should mention that we already have this sequential number as well; the batch id. So, the combination of scriptSessionId and batchId uniquely identifies every call to the server, including file uploads.

My original invocationId used scriptSessionId + batchId but I moved to a random number to support a DWR mode without script sessions.  
I believe it might have been me asking you not to depend on script sessions, and I think it is good to support other configurations.
Perhaps I could check if scriptSessionId is null and only use the random number in this case.
As I wrote earlier I think we should avoid trying to generate a unique id in the DWR client layer, and leave this to the application code when the default script session based implementation is not used. With this I mean we should not have any random number generation at all in our code, not even as a fallback.
 
About a potentially unset scriptSessionId (because of a fresh page), I think the following behaviour could be appropriate:
 
Default upload:
Remote.uploadFile(dwr.util.byId("myFile"), 
{
    callback: ...,
    progressCallback:  ... 
});
 
Here the default ScriptSession-based incovationId is used, so the client layer needs to know the scriptSessionId before sending along the upload, as we would otherwise not know what invocationId to poll progress about.
Thus, if scriptSessionId has not yet been set we need to send a pre-flight call that retrieves this id (this is always done by the first call from a fresh page, f ex by reverse Ajax polls when using that mode). After the return of that request we can then start the real upload request.
I have to disagree here. This adds server load for nothing in return. Keep in mind that the invocationId has not to be unique (at least for file upload and even more so with a session manager).
 
Custom upload:
Remote.uploadFile(dwr.util.byId("myFile"), 
{
    callback: ...,
    progressCallback:  ...,
    invocationId: ...
});
 
Here a custom incovationId is used, so we already know what invocationId to poll for in the progress handling. No scriptSessionId or pre-flight call needed.
Summing these suggestions up, this is how I would expect them to work:
 
Specifying no progress callback means no progress handling will be done. The returned Deferred object allows us to manually check progress or cancel upload:
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...
    }
);
dwr.engine.getProgress(deferredInvocation) // sends progress check request
dwr.engine.isCompleted(deferredInvocation) // internal flag, no request needed
dwr.engine.cancel(deferredInvocation)
[Some more thought could be put into these method names]
Specifying a progress callback means progress handling will be active (in this case with scriptSessionId algorithm):
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(...) {},
        progressInterval: 500 // msec
    }
);
And finally, also specifying an invocationId means that we override the scriptSessionId algorithm with our own:
var deferredInvocation = Remote.uploadFile(
    dwr.util.byId("myFile"),
    {
        callback: ...,
        progressCallback: function(...) {},
        progressInterval: 500, // msec
        invocationId: "my Internet-wide unique string"
    }
);

This works for me... I originally considered returning an object from a DWR call but wasn't sold on the idea since in sync mode {async: false} DWR returns the remote response. I wasn't sure of the implications here. This will obviously require a bit more work to implement this approach.
Yes, I thought about the sync thing as well. Conceptually though, when you use a sync call you have already said that you want to use JavaScript's single thread to wait for the operation to complete before doing anything else, including updating progress (most browsers also freeze the UI during a sync call).
It is only when you do an async call that you could normally let your single JavaScript thread do other work during the upload, like updating progress.
So I think it is quite "correct", and follows standard patterns, to return a handle to the running operation as a return value only from an async call, and not do this for sync calls (it is natural for sync calls to return the resulting value).
 
Also, normally you cannot use sync mode for file uploads as sync requires XHR (though Firefox has added file upload capabilities that can be used by XHR). 
If the scriptSessionId suggestion above works out, then I guess the default upload manager should store progress on the script session.

It's trivial to plug in a ScriptSessionUploadManager  
Yes, should be.
Another (default) stores to a local map. 
I'm not sure what you mean with "local map"?

I just mean a member variable on the DefaultUploadManager singleton  
Ah, right, the application global version. This is the hardest one to make secure (user code-generated invocationIds must be unique over all current users of the site) so this should not be the default upload manager. 
I remember from a previous discussion that it was suggested that progress could be delivered by Reverse Ajax, if active on the page. I'm not sure how much that would complicate things.

I think that reverse ajax polls are less frequent than what is required to update a progress widget. The two could be combined in the future but I'm not going to attempt this at this stage. 
I think the goal in that previous discussion was to use reverse ajax in streaming mode so updates are transmitted immediately, but within the same request. Ie, a single poll and then pushing progress from the server into the poll request's response stream every 500ms or whatever has been set. This certainly doesn't have to be implemented now, but it would be good if you could take a quick look to see if it will be possible to add this feature within the current public APIs we are designing now.

Reverse AJAX should be optional in any case. And I'm not sure I see the benefits of RA here though given that the polling only lasts as long as the file upload.
 
 
Best regards
Mike


RE: File upload progress

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Lance wrote:

2009/6/9 Mike Wilson <mikewse@...>
Lance wrote:
2009/6/7 Mike Wilson <mikewse@...>
Lance wrote:  
dwr.engine.cancelUpload("myUpload");
</javascript>

engine.js generates an invocationId which is passed to the server which can be used to cancel an upload or poll it's current progress.
2) Generic progress and cancellation
As you mentioned in an earlier mail, it could be interesting to provide a generic progress/cancellation mechanism for all calls, not just for file uploads. I then think it would be natural to return an object from any async call following the Deferred/Future pattern. This object could be used for asking about progress, completion status or to trigger cancellation, and would replace (but possibly contain) the invocationId in your example.
If providing progress for all kinds of requests, then we can not depend on always getting a percentage to the progress callback, as we typically don't know the size of outbound data. The parameters could instead be designed this way:
function(transferredBytes, totalBytes)
and the totalBytes would only be set in the cases when we do have that information (and could easily be converted to a percentage). When totalBytes is undefined, a progress dialog could still show the running transferredBytes count.

Hmm... this locks us into a file upload now rather than a more generic process percentage. I'm not 100% on this but could be talked into it. 
My point was actually the opposite, ie not to lock us into file upload ;-).
Normally, it is only at upload (file or data) that we know the total number of bytes we are going to send and can thus calculate the percentage. If we want to use generic progress handling for large sets of outbound data ("download") then we normally don't know the total size at it is processed in a streaming fashion. This makes the percentage impossible to calculate for this case, and therefore I suggested the "transferred byte count so far" to be used in the progress callback.
 
Also, I believe that it could be interesting for the progress indicator to be able, at will, to show the byte count and not just the percentage. Percentages can easily be derived from the bytes if the total is available.

By generic I am talking about for all long running tasks, not necessarily involving bytes. I've seen a really good implementation of a progress indicator where processes were able to return strings stating which stage they were at. A progress manager would after a while collect the results of the same process and would be able to estimate the percentage complete on the current stage and previous results. It's not perfect but the progress widget moved quite steadily after it had collected a big enough survey. Food for thought anyway.  
I'm all for something that is compatible with as many cases as possible. The problem I was seeing with the "percentage" suggestion was that we have no way to solve it for outbound data in DWR, but it is always easy to count bytes.
 
I see how you mean that a "learning" progress manager could use heuristics and historical data to guess a percentage. This is quite advanced functionality though, and will probably not show up in trunk anytime soon. But I like the idea of making it possible.
 
The progress manager based on process stage sounds more like something you integrate with application code, ie it is non-DWR code on the server-side that delivers the progress information. This is probably an interesting future use-case if we go for generic progress handling, so it could well get to influence some of the current design decisions.
 
I'm fine with the use-cases you've suggested and it would great to make an API that could cater for the different needs presented.
To sum up, it seems like in some use-cases we have a byte count but no percentage, and in others we have a percentage but no byte count. I think the byte count, when applicable, is valuable for some use-cases ("Uploaded 5.7MB of 12MB") so maybe we should have an API that can work with both bytes and percentages?
I think the goal in that previous discussion was to use reverse ajax in streaming mode so updates are transmitted immediately, but within the same request. Ie, a single poll and then pushing progress from the server into the poll request's response stream every 500ms or whatever has been set. This certainly doesn't have to be implemented now, but it would be good if you could take a quick look to see if it will be possible to add this feature within the current public APIs we are designing now.

I must say that my knowlege of how comet works is more theoretical than practical. Can you lead me towards some of the classes you'd like me to take a look at? 
Oh, you probably don't have to look so much at how it is implemented as long as you have the general idea of it. The thing is that it would probably work the other way around, ie the timer loop that triggers each progress transmission would sit on the server. Each time it triggers it would ask about progress in the server, and then push a progress method call, maybe something like:
dwr.engine.remote.handleProgress(batchId, progressinfo...)
to the client through the reverse ajax channel.
The handleProgress method would then call the appropriate progressCallbacks registered on the batch.
 
Best regards
Mike

RE: File upload progress

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Jose wrote:

On Tue, Jun 9, 2009 at 8:04 PM, Mike Wilson <mikewse@...> wrote:
 
About a potentially unset scriptSessionId (because of a fresh page), I think the following behaviour could be appropriate:
 
Default upload:
Remote.uploadFile(dwr.util.byId("myFile"), 
{
    callback: ...,
    progressCallback:  ... 
});
 
Here the default ScriptSession-based incovationId is used, so the client layer needs to know the scriptSessionId before sending along the upload, as we would otherwise not know what invocationId to poll progress about.
Thus, if scriptSessionId has not yet been set we need to send a pre-flight call that retrieves this id (this is always done by the first call from a fresh page, f ex by reverse Ajax polls when using that mode). After the return of that request we can then start the real upload request.
I have to disagree here. This adds server load for nothing in return.  
We are usually on the same page when it comes to saving requests so I'll try to convince you here ;-).
If you think back on our discussion about static engine.js quite a long time ago, I think you will agree with me. In 2.x engine.js contains the scriptSessionId and has to be delivered "fresh" for every page. For 3.0 Joe first changed this so engine.js was static, but an extra request was then sent on every page load to fetch the scriptSessionId. You and I wanted to avoid the extra request so we instead devised a solution where the scriptSessionId is unknown until the first (user-triggered) call goes to the server. We then had to avoid that two requests were sent in parallel as long as the scriptSessionId was unknown, as this would otherwise create two different ids for the same page. That's why engine.js starts up in ordered mode until it has the scriptSessionId.
 
Now, the whole thing of progress handling is about sending two requests in parallel. One long request that we want to monitor, and many small ones to get the progress. If the calls would start in parallel before we have a scriptSessionId then they will connect to different script sessions. Note that to avoid this, currently engine.js delays one of the calls until the first one returns (="ordered mode").
 
I question the effect of additional server load that you mention; you are about to send maybe 20-30 extra requests just to update a progress bar and you are concerned about avoiding one request to "initialize the progress handling", if needed?
And the extra request will only need to be sent IFF we are actually watching progress for this operation, and IFF there has not been any other request already sent from this page (unlikely), and IFF the user code is using the script session based upload.
Keep in mind that the invocationId has not to be unique (at least for file upload and even more so with a session manager).
The "total" fingerprint of the invocationId must be unique, but depending on the server-side manager you will automatically have it "prefixed" or "scoped" (this is just logical reasoning and doesn't mean there is any string concat going on):
 
ScriptSessionManager: scriptSessionId + invocationId(=batchId)
SessionManager: JSESSIONID + invocationId
ApplicationManager: invocationId
 
For the script session case it is enough to use a sequentially incremented invocationId, as we are guaranteed that we are the only page with this scriptSessionId.
For the session case we may be several browser windows/tabs sharing the same JSESSIONID, so a simple increment is not enough.
For the application case (shudder), we need to provide an invocationId that is globally unique over all user sessions on the site, to avoid interference between users.
 
Maybe the real point you are making is that we shouldn't be using the scriptSessionId based version at all, and focus on the other variants. If we do, then we have to adapt for the hardest one, which is the application based, as we (currently) in the client layer don't know which manager they're using.
Providing a guaranteed globally unique id generated in the client is something Joe looked a lot at for script sessions, and he didn't want to risk the consequences of doing it.
This is why I think we by default should reuse the global id we already have (scriptSessionId), and avoid inventing a new ad-hoc id. User code can override it when not using the default implementation.
 
But then again, if you can provide a guaranteed globally unique id generation algorithm for the client, then we could improve script session handling in general instead...
I remember from a previous discussion that it was suggested that progress could be delivered by Reverse Ajax, if active on the page. I'm not sure how much that would complicate things.

I think that reverse ajax polls are less frequent than what is required to update a progress widget. The two could be combined in the future but I'm not going to attempt this at this stage. 
I think the goal in that previous discussion was to use reverse ajax in streaming mode so updates are transmitted immediately, but within the same request. Ie, a single poll and then pushing progress from the server into the poll request's response stream every 500ms or whatever has been set. This certainly doesn't have to be implemented now, but it would be good if you could take a quick look to see if it will be possible to add this feature within the current public APIs we are designing now.

Reverse AJAX should be optional in any case. And I'm not sure I see the benefits of RA here though given that the polling only lasts as long as the file upload.
Certainly, I'm not saying we should implement RA progress handling. But it has been discussed before and I don't remember the arguments. Anybody can fill in?
A contrived case would be hitting the two-connection limit when doing
- reverse ajax streaming connection
- file upload
- progress calls as normal (non-RA) calls
at the same time (you can't have all three of them).
 
Best regards
Mike

Re: File upload progress

by Lance Java :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I also came up with a JSP taglib suggestion to avoid the initial request

Please keep in mind that in all of my talk on the subject. I have meant that invocationId is an application wide unique identifier for the invocation (ie scriptSessionId + batchId). I have seen mike using it to mean batch id. I'd prefer to stick with my terminology if that's ok.

2009/6/10 Mike Wilson <mikewse@...>
Jose wrote:

On Tue, Jun 9, 2009 at 8:04 PM, Mike Wilson <mikewse@...> wrote:
 
About a potentially unset scriptSessionId (because of a fresh page), I think the following behaviour could be appropriate:
 
Default upload:
Remote.uploadFile(dwr.util.byId("myFile"), 
{
    callback: ...,
    progressCallback:  ... 
});
 
Here the default ScriptSession-based incovationId is used, so the client layer needs to know the scriptSessionId before sending along the upload, as we would otherwise not know what invocationId to poll progress about.
Thus, if scriptSessionId has not yet been set we need to send a pre-flight call that retrieves this id (this is always done by the first call from a fresh page, f ex by reverse Ajax polls when using that mode). After the return of that request we can then start the real upload request.
I have to disagree here. This adds server load for nothing in return.  
We are usually on the same page when it comes to saving requests so I'll try to convince you here ;-).
If you think back on our discussion about static engine.js quite a long time ago, I think you will agree with me. In 2.x engine.js contains the scriptSessionId and has to be delivered "fresh" for every page. For 3.0 Joe first changed this so engine.js was static, but an extra request was then sent on every page load to fetch the scriptSessionId. You and I wanted to avoid the extra request so we instead devised a solution where the scriptSessionId is unknown until the first (user-triggered) call goes to the server. We then had to avoid that two requests were sent in parallel as long as the scriptSessionId was unknown, as this would otherwise create two different ids for the same page. That's why engine.js starts up in ordered mode until it has the scriptSessionId.
 
Now, the whole thing of progress handling is about sending two requests in parallel. One long request that we want to monitor, and many small ones to get the progress. If the calls would start in parallel before we have a scriptSessionId then they will connect to different script sessions. Note that to avoid this, currently engine.js delays one of the calls until the first one returns (="ordered mode").
 
I question the effect of additional server load that you mention; you are about to send maybe 20-30 extra requests just to update a progress bar and you are concerned about avoiding one request to "initialize the progress handling", if needed?
And the extra request will only need to be sent IFF we are actually watching progress for this operation, and IFF there has not been any other request already sent from this page (unlikely), and IFF the user code is using the script session based upload.
Keep in mind that the invocationId has not to be unique (at least for file upload and even more so with a session manager).
The "total" fingerprint of the invocationId must be unique, but depending on the server-side manager you will automatically have it "prefixed" or "scoped" (this is just logical reasoning and doesn't mean there is any string concat going on):
 
ScriptSessionManager: scriptSessionId + invocationId(=batchId)
SessionManager: JSESSIONID + invocationId
ApplicationManager: invocationId
 
For the script session case it is enough to use a sequentially incremented invocationId, as we are guaranteed that we are the only page with this scriptSessionId.
For the session case we may be several browser windows/tabs sharing the same JSESSIONID, so a simple increment is not enough.
For the application case (shudder), we need to provide an invocationId that is globally unique over all user sessions on the site, to avoid interference between users.
 
Maybe the real point you are making is that we shouldn't be using the scriptSessionId based version at all, and focus on the other variants. If we do, then we have to adapt for the hardest one, which is the application based, as we (currently) in the client layer don't know which manager they're using.
Providing a guaranteed globally unique id generated in the client is something Joe looked a lot at for script sessions, and he didn't want to risk the consequences of doing it.
This is why I think we by default should reuse the global id we already have (scriptSessionId), and avoid inventing a new ad-hoc id. User code can override it when not using the default implementation.
 
But then again, if you can provide a guaranteed globally unique id generation algorithm for the client, then we could improve script session handling in general instead...
I remember from a previous discussion that it was suggested that progress could be delivered by Reverse Ajax, if active on the page. I'm not sure how much that would complicate things.

I think that reverse ajax polls are less frequent than what is required to update a progress widget. The two could be combined in the future but I'm not going to attempt this at this stage. 
I think the goal in that previous discussion was to use reverse ajax in streaming mode so updates are transmitted immediately, but within the same request. Ie, a single poll and then pushing progress from the server into the poll request's response stream every 500ms or whatever has been set. This certainly doesn't have to be implemented now, but it would be good if you could take a quick look to see if it will be possible to add this feature within the current public APIs we are designing now.

Reverse AJAX should be optional in any case. And I'm not sure I see the benefits of RA here though given that the polling only lasts as long as the file upload.
Certainly, I'm not saying we should implement RA progress handling. But it has been discussed before and I don't remember the arguments. Anybody can fill in?
A contrived case would be hitting the two-connection limit when doing
- reverse ajax streaming connection
- file upload
- progress calls as normal (non-RA) calls
at the same time (you can't have all three of them).
 
Best regards
Mike


RE: File upload progress

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Lance wrote:

I also came up with a JSP taglib suggestion to avoid the initial request
Right, that's good for JSP users.
Please keep in mind that in all of my talk on the subject. I have meant that invocationId is an application wide unique identifier for the invocation (ie scriptSessionId + batchId). I have seen mike using it to mean batch id. I'd prefer to stick with my terminology if that's ok. 
I think we mean the same thing, I am just pointing out that depending on the server-side manager the supplied invocationId is working inside different-sized scopes, and therefore have different requirements on "how unique" we have to make it. For a session-based manager the "effective" invocationId is really JSESSIONID + the invocationId from engine.js.
 
Isn't it so, that when you say "application wide" you are assuming that you are using the application global upload manager, which doesn't add anything to the "effective invocationId"?
 
Best regards
Mike

Re: File upload progress

by Lance Java :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I was hoping that the invocationId generation technique did not care about which upload manager implementation was being used. It therefore needs to assume the worst (unique to the application). The invocationId is generated in javascript. This may include a serverside generated token (ie scriptSessionId).

2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I also came up with a JSP taglib suggestion to avoid the initial request
Right, that's good for JSP users.
Please keep in mind that in all of my talk on the subject. I have meant that invocationId is an application wide unique identifier for the invocation (ie scriptSessionId + batchId). I have seen mike using it to mean batch id. I'd prefer to stick with my terminology if that's ok. 
I think we mean the same thing, I am just pointing out that depending on the server-side manager the supplied invocationId is working inside different-sized scopes, and therefore have different requirements on "how unique" we have to make it. For a session-based manager the "effective" invocationId is really JSESSIONID + the invocationId from engine.js.
 
Isn't it so, that when you say "application wide" you are assuming that you are using the application global upload manager, which doesn't add anything to the "effective invocationId"?
 
Best regards
Mike


RE: File upload progress

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Lance wrote:

I was hoping that the invocationId generation technique did not care about which upload manager implementation was being used. It therefore needs to assume the worst (unique to the application). The invocationId is generated in javascript. This may include a serverside generated token (ie scriptSessionId). 
Ah, ok, I don't mind either way here, and now I understand your point about a "complete" invocationId. 
One could say that adding the scriptSessionId to the invocationId in client code is redundant when a ScriptSession-based progress manager is used (as invocationIds are scoped on the current script session) but it certainly doesn't do any harm. And as you say, it lets you choose any progress manager (although it would be natural to choose the ScriptSession-based manager when the invocationId is based on scriptSessionId). No worries there.
 
Do we agree to use the scriptSessionId-based algorithm as default, and have the user implement their own algorithm in case they want something different?
 
Best regards
Mike
2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I also came up with a JSP taglib suggestion to avoid the initial request
Right, that's good for JSP users.
Please keep in mind that in all of my talk on the subject. I have meant that invocationId is an application wide unique identifier for the invocation (ie scriptSessionId + batchId). I have seen mike using it to mean batch id. I'd prefer to stick with my terminology if that's ok. 
I think we mean the same thing, I am just pointing out that depending on the server-side manager the supplied invocationId is working inside different-sized scopes, and therefore have different requirements on "how unique" we have to make it. For a session-based manager the "effective" invocationId is really JSESSIONID + the invocationId from engine.js.
 
Isn't it so, that when you say "application wide" you are assuming that you are using the application global upload manager, which doesn't add anything to the "effective invocationId"?
 
Best regards
Mike

Re: File upload progress

by Lance Java :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Firstly, I think I'll change UploadManager to be ProgressManager.

How's this for a solution.

Have a new flag in engine.js:
   dwr.engine._trustRandomForInvocationId

I realise random numbers are generated by current time so 2 browsers can get the same random at the same time. If using a HttpSessionProgressManager there's no real chance of a clash though.

When generating an invocation id (clientside):
1. If (scriptSessionId != null) use scriptSessionId + batchId
2. If (scriptSessionId == null && trustRandomForInvocationId) use a random number for invocationId
3. Make a serverside call then use method 1.

An extension to this, a new method could be added to the ProgressManager interface.
   public boolean isTrustRandomForInvocationId()

This would return false for the global manager and true for HttpSessionProgressManager and ScriptSessionProgressManager.

We could then use this method when generating engine.js and set the default for the flag:
   dwr.engine._trustRandomForInvocationId = ${progressManager.trustRandomForInvocationId}

The developer can override this in javascript:
  dwr.engine.setTrustRandomForInvocationId(false);


2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I was hoping that the invocationId generation technique did not care about which upload manager implementation was being used. It therefore needs to assume the worst (unique to the application). The invocationId is generated in javascript. This may include a serverside generated token (ie scriptSessionId). 
Ah, ok, I don't mind either way here, and now I understand your point about a "complete" invocationId. 
One could say that adding the scriptSessionId to the invocationId in client code is redundant when a ScriptSession-based progress manager is used (as invocationIds are scoped on the current script session) but it certainly doesn't do any harm. And as you say, it lets you choose any progress manager (although it would be natural to choose the ScriptSession-based manager when the invocationId is based on scriptSessionId). No worries there.
 
Do we agree to use the scriptSessionId-based algorithm as default, and have the user implement their own algorithm in case they want something different?
 
Best regards
Mike
2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I also came up with a JSP taglib suggestion to avoid the initial request
Right, that's good for JSP users.
Please keep in mind that in all of my talk on the subject. I have meant that invocationId is an application wide unique identifier for the invocation (ie scriptSessionId + batchId). I have seen mike using it to mean batch id. I'd prefer to stick with my terminology if that's ok. 
I think we mean the same thing, I am just pointing out that depending on the server-side manager the supplied invocationId is working inside different-sized scopes, and therefore have different requirements on "how unique" we have to make it. For a session-based manager the "effective" invocationId is really JSESSIONID + the invocationId from engine.js.
 
Isn't it so, that when you say "application wide" you are assuming that you are using the application global upload manager, which doesn't add anything to the "effective invocationId"?
 
Best regards
Mike


RE: File upload progress

by mikewse :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I'd like to first settle if we should ship an alternative "id" algorithm in our codebase at all.
 
Ie, do we want to provide and maintain a separate client-side id algorithm for progress handling when we already have the scriptSessionId+batchId algorithm solving the same problem?
If I am the only one against providing the alternative algorithm, then no problem, let's go for it.
Joe: you've been doing work in this area before, can we hear your input on this?
 
Depending on this decision we can then continue the discussion on the looks of the API.
 
Best regards
Mike


From: Lance Java [mailto:lance.java@...]
Sent: den 11 juni 2009 10:01
To: users@...
Subject: Re: [dwr-user] File upload progress

Firstly, I think I'll change UploadManager to be ProgressManager.

How's this for a solution.

Have a new flag in engine.js:
   dwr.engine._trustRandomForInvocationId

I realise random numbers are generated by current time so 2 browsers can get the same random at the same time. If using a HttpSessionProgressManager there's no real chance of a clash though.

When generating an invocation id (clientside):
1. If (scriptSessionId != null) use scriptSessionId + batchId
2. If (scriptSessionId == null && trustRandomForInvocationId) use a random number for invocationId
3. Make a serverside call then use method 1.

An extension to this, a new method could be added to the ProgressManager interface.
   public boolean isTrustRandomForInvocationId()

This would return false for the global manager and true for HttpSessionProgressManager and ScriptSessionProgressManager.

We could then use this method when generating engine.js and set the default for the flag:
   dwr.engine._trustRandomForInvocationId = ${progressManager.trustRandomForInvocationId}

The developer can override this in javascript:
  dwr.engine.setTrustRandomForInvocationId(false);


2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I was hoping that the invocationId generation technique did not care about which upload manager implementation was being used. It therefore needs to assume the worst (unique to the application). The invocationId is generated in javascript. This may include a serverside generated token (ie scriptSessionId). 
Ah, ok, I don't mind either way here, and now I understand your point about a "complete" invocationId. 
One could say that adding the scriptSessionId to the invocationId in client code is redundant when a ScriptSession-based progress manager is used (as invocationIds are scoped on the current script session) but it certainly doesn't do any harm. And as you say, it lets you choose any progress manager (although it would be natural to choose the ScriptSession-based manager when the invocationId is based on scriptSessionId). No worries there.
 
Do we agree to use the scriptSessionId-based algorithm as default, and have the user implement their own algorithm in case they want something different?
 
Best regards
Mike
2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I also came up with a JSP taglib suggestion to avoid the initial request
Right, that's good for JSP users.
Please keep in mind that in all of my talk on the subject. I have meant that invocationId is an application wide unique identifier for the invocation (ie scriptSessionId + batchId). I have seen mike using it to mean batch id. I'd prefer to stick with my terminology if that's ok. 
I think we mean the same thing, I am just pointing out that depending on the server-side manager the supplied invocationId is working inside different-sized scopes, and therefore have different requirements on "how unique" we have to make it. For a session-based manager the "effective" invocationId is really JSESSIONID + the invocationId from engine.js.
 
Isn't it so, that when you say "application wide" you are assuming that you are using the application global upload manager, which doesn't add anything to the "effective invocationId"?
 
Best regards
Mike


Re: File upload progress

by Lance Java :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

To have a non-null script session id you need a serverside hit. This flag gives the developer the option not to do the serverside hit.
I'm all for giving the developer more control as long as they know what they're doing.

2009/6/11 Mike Wilson <mikewse@...>
I'd like to first settle if we should ship an alternative "id" algorithm in our codebase at all.
 
Ie, do we want to provide and maintain a separate client-side id algorithm for progress handling when we already have the scriptSessionId+batchId algorithm solving the same problem?
If I am the only one against providing the alternative algorithm, then no problem, let's go for it.
Joe: you've been doing work in this area before, can we hear your input on this?
 
Depending on this decision we can then continue the discussion on the looks of the API.
 
Best regards
Mike


From: Lance Java [mailto:lance.java@...]
Sent: den 11 juni 2009 10:01
To: users@...
Subject: Re: [dwr-user] File upload progress

Firstly, I think I'll change UploadManager to be ProgressManager.

How's this for a solution.

Have a new flag in engine.js:
   dwr.engine._trustRandomForInvocationId

I realise random numbers are generated by current time so 2 browsers can get the same random at the same time. If using a HttpSessionProgressManager there's no real chance of a clash though.

When generating an invocation id (clientside):
1. If (scriptSessionId != null) use scriptSessionId + batchId
2. If (scriptSessionId == null && trustRandomForInvocationId) use a random number for invocationId
3. Make a serverside call then use method 1.

An extension to this, a new method could be added to the ProgressManager interface.
   public boolean isTrustRandomForInvocationId()

This would return false for the global manager and true for HttpSessionProgressManager and ScriptSessionProgressManager.

We could then use this method when generating engine.js and set the default for the flag:
   dwr.engine._trustRandomForInvocationId = ${progressManager.trustRandomForInvocationId}

The developer can override this in javascript:
  dwr.engine.setTrustRandomForInvocationId(false);


2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I was hoping that the invocationId generation technique did not care about which upload manager implementation was being used. It therefore needs to assume the worst (unique to the application). The invocationId is generated in javascript. This may include a serverside generated token (ie scriptSessionId). 
Ah, ok, I don't mind either way here, and now I understand your point about a "complete" invocationId. 
One could say that adding the scriptSessionId to the invocationId in client code is redundant when a ScriptSession-based progress manager is used (as invocationIds are scoped on the current script session) but it certainly doesn't do any harm. And as you say, it lets you choose any progress manager (although it would be natural to choose the ScriptSession-based manager when the invocationId is based on scriptSessionId). No worries there.
 
Do we agree to use the scriptSessionId-based algorithm as default, and have the user implement their own algorithm in case they want something different?
 
Best regards
Mike
2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I also came up with a JSP taglib suggestion to avoid the initial request
Right, that's good for JSP users.
Please keep in mind that in all of my talk on the subject. I have meant that invocationId is an application wide unique identifier for the invocation (ie scriptSessionId + batchId). I have seen mike using it to mean batch id. I'd prefer to stick with my terminology if that's ok. 
I think we mean the same thing, I am just pointing out that depending on the server-side manager the supplied invocationId is working inside different-sized scopes, and therefore have different requirements on "how unique" we have to make it. For a session-based manager the "effective" invocationId is really JSESSIONID + the invocationId from engine.js.
 
Isn't it so, that when you say "application wide" you are assuming that you are using the application global upload manager, which doesn't add anything to the "effective invocationId"?
 
Best regards
Mike



Re: File upload progress

by Lance Java :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I can finally see where you are coming from.... no random required

Just so we're sure... these are the cases I'd like to support

1. scriptSessions enabled + ScriptSessionProgressManager
2. scriptSessions disabled + HttpSessionProgressManager
3. scriptSessions disabled + GlobalProgressManager

So, I guess in case 1 we can use batch id (dwr.engine._useBatchIdForInvocationId)
Therefore no serverside hit required initially

And in cases 2 and 3 we need a serverside token before doing progress.

I have never used stateless mode (<dwr:config-param name="interactivity" value="stateless" />)
Is dwr.engine._scriptSessionId populated after an invocation in stateless mode?

Lance.





2009/6/11 Lance Java <lance.java@...>
To have a non-null script session id you need a serverside hit. This flag gives the developer the option not to do the serverside hit.
I'm all for giving the developer more control as long as they know what they're doing.

2009/6/11 Mike Wilson <mikewse@...>

I'd like to first settle if we should ship an alternative "id" algorithm in our codebase at all.
 
Ie, do we want to provide and maintain a separate client-side id algorithm for progress handling when we already have the scriptSessionId+batchId algorithm solving the same problem?
If I am the only one against providing the alternative algorithm, then no problem, let's go for it.
Joe: you've been doing work in this area before, can we hear your input on this?
 
Depending on this decision we can then continue the discussion on the looks of the API.
 
Best regards
Mike


From: Lance Java [mailto:lance.java@...]
Sent: den 11 juni 2009 10:01
To: users@...
Subject: Re: [dwr-user] File upload progress

Firstly, I think I'll change UploadManager to be ProgressManager.

How's this for a solution.

Have a new flag in engine.js:
   dwr.engine._trustRandomForInvocationId

I realise random numbers are generated by current time so 2 browsers can get the same random at the same time. If using a HttpSessionProgressManager there's no real chance of a clash though.

When generating an invocation id (clientside):
1. If (scriptSessionId != null) use scriptSessionId + batchId
2. If (scriptSessionId == null && trustRandomForInvocationId) use a random number for invocationId
3. Make a serverside call then use method 1.

An extension to this, a new method could be added to the ProgressManager interface.
   public boolean isTrustRandomForInvocationId()

This would return false for the global manager and true for HttpSessionProgressManager and ScriptSessionProgressManager.

We could then use this method when generating engine.js and set the default for the flag:
   dwr.engine._trustRandomForInvocationId = ${progressManager.trustRandomForInvocationId}

The developer can override this in javascript:
  dwr.engine.setTrustRandomForInvocationId(false);


2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I was hoping that the invocationId generation technique did not care about which upload manager implementation was being used. It therefore needs to assume the worst (unique to the application). The invocationId is generated in javascript. This may include a serverside generated token (ie scriptSessionId). 
Ah, ok, I don't mind either way here, and now I understand your point about a "complete" invocationId. 
One could say that adding the scriptSessionId to the invocationId in client code is redundant when a ScriptSession-based progress manager is used (as invocationIds are scoped on the current script session) but it certainly doesn't do any harm. And as you say, it lets you choose any progress manager (although it would be natural to choose the ScriptSession-based manager when the invocationId is based on scriptSessionId). No worries there.
 
Do we agree to use the scriptSessionId-based algorithm as default, and have the user implement their own algorithm in case they want something different?
 
Best regards
Mike
2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I also came up with a JSP taglib suggestion to avoid the initial request
Right, that's good for JSP users.
Please keep in mind that in all of my talk on the subject. I have meant that invocationId is an application wide unique identifier for the invocation (ie scriptSessionId + batchId). I have seen mike using it to mean batch id. I'd prefer to stick with my terminology if that's ok. 
I think we mean the same thing, I am just pointing out that depending on the server-side manager the supplied invocationId is working inside different-sized scopes, and therefore have different requirements on "how unique" we have to make it. For a session-based manager the "effective" invocationId is really JSESSIONID + the invocationId from engine.js.
 
Isn't it so, that when you say "application wide" you are assuming that you are using the application global upload manager, which doesn't add anything to the "effective invocationId"?
 
Best regards
Mike




Re: File upload progress

by Lance Java :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Although in case 2 I'd argue that a random is good enough.

2009/6/11 Lance Java <lance.java@...>
I can finally see where you are coming from.... no random required

Just so we're sure... these are the cases I'd like to support

1. scriptSessions enabled + ScriptSessionProgressManager
2. scriptSessions disabled + HttpSessionProgressManager
3. scriptSessions disabled + GlobalProgressManager

So, I guess in case 1 we can use batch id (dwr.engine._useBatchIdForInvocationId)
Therefore no serverside hit required initially

And in cases 2 and 3 we need a serverside token before doing progress.

I have never used stateless mode (<dwr:config-param name="interactivity" value="stateless" />)
Is dwr.engine._scriptSessionId populated after an invocation in stateless mode?

Lance.





2009/6/11 Lance Java <lance.java@...>

To have a non-null script session id you need a serverside hit. This flag gives the developer the option not to do the serverside hit.
I'm all for giving the developer more control as long as they know what they're doing.

2009/6/11 Mike Wilson <mikewse@...>

I'd like to first settle if we should ship an alternative "id" algorithm in our codebase at all.
 
Ie, do we want to provide and maintain a separate client-side id algorithm for progress handling when we already have the scriptSessionId+batchId algorithm solving the same problem?
If I am the only one against providing the alternative algorithm, then no problem, let's go for it.
Joe: you've been doing work in this area before, can we hear your input on this?
 
Depending on this decision we can then continue the discussion on the looks of the API.
 
Best regards
Mike


From: Lance Java [mailto:lance.java@...]
Sent: den 11 juni 2009 10:01
To: users@...
Subject: Re: [dwr-user] File upload progress

Firstly, I think I'll change UploadManager to be ProgressManager.

How's this for a solution.

Have a new flag in engine.js:
   dwr.engine._trustRandomForInvocationId

I realise random numbers are generated by current time so 2 browsers can get the same random at the same time. If using a HttpSessionProgressManager there's no real chance of a clash though.

When generating an invocation id (clientside):
1. If (scriptSessionId != null) use scriptSessionId + batchId
2. If (scriptSessionId == null && trustRandomForInvocationId) use a random number for invocationId
3. Make a serverside call then use method 1.

An extension to this, a new method could be added to the ProgressManager interface.
   public boolean isTrustRandomForInvocationId()

This would return false for the global manager and true for HttpSessionProgressManager and ScriptSessionProgressManager.

We could then use this method when generating engine.js and set the default for the flag:
   dwr.engine._trustRandomForInvocationId = ${progressManager.trustRandomForInvocationId}

The developer can override this in javascript:
  dwr.engine.setTrustRandomForInvocationId(false);


2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I was hoping that the invocationId generation technique did not care about which upload manager implementation was being used. It therefore needs to assume the worst (unique to the application). The invocationId is generated in javascript. This may include a serverside generated token (ie scriptSessionId). 
Ah, ok, I don't mind either way here, and now I understand your point about a "complete" invocationId. 
One could say that adding the scriptSessionId to the invocationId in client code is redundant when a ScriptSession-based progress manager is used (as invocationIds are scoped on the current script session) but it certainly doesn't do any harm. And as you say, it lets you choose any progress manager (although it would be natural to choose the ScriptSession-based manager when the invocationId is based on scriptSessionId). No worries there.
 
Do we agree to use the scriptSessionId-based algorithm as default, and have the user implement their own algorithm in case they want something different?
 
Best regards
Mike
2009/6/10 Mike Wilson <mikewse@...>
Lance wrote:

I also came up with a JSP taglib suggestion to avoid the initial request
Right, that's good for JSP users.
Please keep in mind that in all of my talk on the subject. I have meant that invocationId is an application wide unique identifier for the invocation (ie scriptSessionId + batchId). I have seen mike using it to mean batch id. I'd prefer to stick with my terminology if that's ok. 
I think we mean the same thing, I am just pointing out that depending on the server-side manager the supplied invocationId is working inside different-sized scopes, and therefore have different requirements on "how unique" we have to make it. For a session-based manager the "effective" invocationId is really JSESSIONID + the invocationId from engine.js.
 
Isn't it so, that when you say "application wide" you are assuming that you are using the application global upload manager, which doesn't add anything to the "effective invocationId"?
 
Best regards
Mike




< Prev | 1 - 2 - 3 | Next >