Subbu Allamaraju
Goals
- Let portlets use Ajax to submit requests and update their markup without causing full portal or portlet refresh.
- Use script to send requests asynchronously to the portlet
- Participate in action/event/render lifecycle as determined by the type of the request
- Return data (XML, JSON, text etc) or UI (HTML, XHTML) fragments in response
- Use script to process the returned data or UI fragment
- Allow consumers to completely process the life cycle of the portlet that initiated the request as well as any other portlets that become stale due to processing the request. Examples of when markup of other portlets may become stale include event distribution, or changes to public render parameters. When this happens, portals should be able to gather markup of those other portlets, and return it to the UA along with the markup generated by the portlet that initiated the request. In addition, since the portlet that initiated the request will only be interested in the data or markup fragment that it generated, only the portlet-generated response should be returned to the portlet's script.
[RT] Thanks for the rewording of the goals, I think they are much better. A remaining concern is that this first goal mandates the solution involve AJAX. I think the solution should accomodate AJAX, but narrowing in this manner in the goals eliminates other models before they are discussed.
[Subbu] I presume you are referring to other rich client technologoes (e.g flash). From the feedback we are receiveing from developers, the pressing use is specifically for XMLHttpRequest. If the TC feels otherwise, we need to reconsider the goals.
These goals call out for a collaborative solution where in the portlet will use some portal provided means to dispatch asynchronous requests to the consumer.
Approach
Define an XMLPortletRequest interface. Consumers implement this interface and provide it as part of the aggregated page.
Keep this interface semantically and syntactically close to XMLHttpRequest (http://www.w3.org/TR/XMLHttpRequest) for easier adoption and pluggability into JavaScript toolkits. For instance, portlets should be able to replace new XMLHttpRequest() with new XMLPortletRequest() and be able to do Ajax programming. The same applies JavaScript toolkits such as Dojo (http://www.dojotoolkit.org/).
Since XMLPortletRequest will most likely be implemented in JavaScript as a layer on top of XMLHttpRequest, in this proposal, some of the conformance statements have to be kept intentionally weaker than those specified for the XMLHttpRequest.
The XMLPortletRequest Interface
The XMLPortletRequest interface is a script interface implemented by Consumers to allow portlet scripts to perform HTTP client functionality similar to the functionality provided by XMLHttpRequest. The XMLPortletRequest is modeled after the XMLHttpRequest, and as such, unless stated otherwise, most of the concepts, behavior (including security constraints and considerations) of the XMLHttpRequest also apply to XMLPortletRequest.
The XMLPortletRequest is intended to be used by a portlets as a replacement of XMLHttpRequest so as to take advantage of the lifecycle and state management features offered by the WSRP protocol.
The XMLPortletRequest object has the following attributes:
onreadystatechange
readystate
responseText
responseXML
status
statusText
title
The XMLPortletRequest has the following methods:
open(in DOMString method, in DOMString uri)
open(in DOMString method, in DOMString uri, in boolean async)
setRequestHeader(in DOMString header, in DOMString value) [This method will have to be more restrictive than that of XMLHttpRequest's setRequestHeader.]
send(in DOMString data)
send(in Document data)
abort()
getAllResponseHeaders() [The output of this method will provide headers relevant to the portlet only.]
getResponseHeader(in DOMString header) [The output of this method will provide headers relevant to the portlet only.]
Consumer's Responsibilities
Provide an implementation of XMLPortletRequest
When an action URL is submitted via XMLPortletRequest, send a performBlockingInteraction request to the producer, followed by handleEvents and getMarkup requests for any portlets that it considered dirty and require markup generation.
When a render URL is submitted via XMLPortletRequest, send a getMarkup requests to the producer for those portlets that it considered dirty and require markup generation.
- ...
Examples
Portlet Using XMLPortletRequest Directly for Ajax Requests
// The URL is created by using a container provided API - may be an action or render URL
var url = '...';
// This object is provided by the consumer/portal page
var request = new XMLPortletRequest();
request.onreadystatechange = function()
{
if (request.readyState == 4 && request.status == 200) {
if (request.responseText) {
// Process
}
}
}
request.open('GET', url, true);
request.send(null);
Notes
- The URL above is generated by spec-defined means via consumer rewriting or producer writing.
Whether the portlet receives responseText or responseXML depends on the markup returned by the portlet.
Portlets Using a Consumer-Provided Version of Dojo Toolkit
This example illustrates that Consumers can adopt well-known toolkits such as Dojo to XMLPortletRequest. Whether this is possible with other toolkits or not depends on the architecture of those toolkits.
// The URL is created by using a container provided API - may be an action or render URL
var url = '...';
dojo.io.bind({
url: url,
load: function(type, data, evt) {
// Process
},
mimetype: "text/plain"
});
Notes
In this example, the Consumer replaced the factory code used to create XMLHttpRequest to return an instance of XMLPortletRequest. People familiar with the architecture of Dojo would notice that this can done by replacing Dojo's XMLHTTPTransport transport layer.
Benefits
- This is a pure script interface and does not require protocol changes except for any metadata exchange if desired. As such, the proposal is independent of the version of the WSRP protocol.
The interface is syntactically equivalent and semantically weaker than XMLHttpRequest to allow easier adoption in weakly-typed scripting languages such as JavaScript. Except for the code used to obtain an instance of XMLPortletRequest, the rest of the script logic can remain the same, still allowing Consumers to perform browser level aggregation and state updates behind the scenes.
Issues/Resolutions
[Rich] While I like the simplicity of this approach dropping in for Portlets already doing AJAX, I would rather not require that portlets adopt the AJAX programming style. Having the Consumer's framework provide APIs for registering onLoad and onRefresh handlers could allow normal portlet programming with the framework then providing the underlying AJAX usage. I think a fuller range of Portlet-Consumer cooperation to achieve the results of the AJAX style needs to be defined.
[Subbu] I considered that. While it may be possible to compe with such an API hiding the Ajax usage, one key issue is the latency. We can only follow what is already being done by web developers. More importantly, programming model decisions are already being made by various Ajax toolkits, and I'm motivated by a design to keep adoption simple/quick to achieve.
WSRP Wiki