Skip to main content

[jsr362-experts:] Re: Proposed changes to function names in the JavaScript API

  • From: Martin Scott Nicklous < >
  • To:
  • Subject: [jsr362-experts:] Re: Proposed changes to function names in the JavaScript API
  • Date: Thu, 10 Apr 2014 12:48:27 +0200

Hi Neil,

thanks for the very thought provoking recommendations. I have some
questions and comments, see below.


Mit freundlichen Grüßen, / Kind regards,
Scott Nicklous

IBM Deutschland Research & Development GmbH / Vorsitzender des
Aufsichtsrats: Martina Koederitz / Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen / Registergericht: Amtsgericht Stuttgart,
HRB 243294


Neil Griffin 
< >
 wrote on 08.04.2014 17:29:51:

> From: Neil Griffin 
> < >
> To: 
>  ,
> Date: 08.04.2014 17:30
> Subject: [jsr362-experts:] Proposed changes to function names in the
> JavaScript API
>
> Hello Experts,
>
> Regarding the following JavaScript (JS) functions:
>
>     register(portletID, onStateChangeHandler, onErrorHandler)
>     onStateChange(portletState, renderData)
>     createResourceURL(resParms, cacheParm, onErrorHandler)
>     setPortletState(portletState, onErrorHandler)
>     action(actionParameters, formElement, onErrorHandler)
>
> I have the following recommendations...
>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> 1. Namespace JS functions with "portlet" (similar idea to "jsf"
namespace).
>
> var portlet = {};
> portlet.registry = {};

ok, good suggestion. I think we need a name space. Whereby all functions
other than the register() function are returned to the caller of register()
in an object in order to encapsulate those functions for the specific
portlet being registered. See "Ajax Proposal 2e", page 7 - PortletInit
object.

>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> 2. Simplify the signature of the "register" function so that it only
takes
>     one arg, and rename "portletID" to "portletId" to align with JS
naming
>     conventions like document.getElementById()
>
> portlet.register = function(portletId) {
>     var registeredPortlet = {};
>     registeredPortlet['portletId'] = portletId;
>     portlet.registry[portletId] = registeredPortlet;
> }
>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> 3. Rather than pass "onStateChangeHandler" and "onErrorHandler" to the
>     register function, provide the following functions that provide
> more vanilla
>     event registration:
>
>     portlet.addOnEvent = function(portletId, callback) { ... }
>     portlet.addOnError = function(portletId, callback) { ... }

Comments to 2) and (3): I understand the idea of using method names that
conform to past convention because it helps programmers recognize what is
going on. On the other hand, conforming to a naming convention implies that
the function will actually work according to the convention.

In this case, the naming convention would make it seem like we are dealing
with a general-purpose event framework. I'm not sure that is really the
case with the onStateChange callback. The idea behind the onStateChange
method described in the proposal is that it would be called ONLY for those
portlet clients whose state has actually changed. Each portlet being
updated through an onStateChange call would receive different,
portlet-specific data. It would not be a general event that would be
propagated to all portlet clients.

So I would be worried that adding the callbacks through a general
addOnEvent call would imply a contract that the portlet hub would not
fulfill, and would thus actually be confusing to JavaScript programmers who
want to write portelt client code.



>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> 4. Provide a new function for broadcasting events:
>
> portlet.broadcastEvent = function(portletId, eventData) {
>     var portletClient = portlet.registry[portletId];
>     var eventListeners = portletClient.eventListeners;
>     for (var i in eventListeners) {
>         var eventListener = eventListeners[i];
>         if (eventListener) {
>             eventListener.call(null, eventData);
>         }
>     }
> }
>
>     This would make it possible for portlet developers to use the
> Portlet JS API
>     to send developer-defined events between portlet clients. Portal
vendors
>     could broadcast vendor-specific events as well.

I understand the idea, but I don't really understand what the value add
would be compared to the event APIs provided by JavaScript itself. If we
would define events that are to be used in a particular manner that is good
for portlets, then we would need to define those uses and events as well.

One potential use that I see would be if such events were tied into the
regular (server side) portlet eventing infrastructure (somehow). We have a
work item to improve eventing, so maybe we could think in this direction.
But that would go considerably beyond what is described in recommendation
#4.

Note that in the current proposal, the combination of the setPortletState /
onStateChange calls can be thought of as an event mechanism based on public
render parameters. If a portlet sets a PRP through the setPortletState
call, all portlets on the page that are subscribed to that PRP will be
informed.

>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> 5. Rename the "action" function to "portlet.ajax.actionRequest"
> (similar naming
>     as jsf.ajax.request). Also rename "formElement" to "source". In
addition,
>     the Portlet Hub needs to broadcast an 'actionParameters" event so
that
>     other portlets on the portal page have a chance to participate in the
Ajax
>     postback by contributing request parameters. For example, JSF
portlets
>     need to contribute the "javax.faces.ViewState" parameter in order to
>     be able to have things work correctly when serveResource() is called.
>
> portlet.ajax = function() {
>     return {
>         actionRequest : function actionRequest(portletId, source) {
>
>             /* Send 'actionParameters' event to each registered portlet
in */
>             /* order to provide each portlet with the opportunity
tosupply */
>             /* additional namespaced parameters before the request */
>             /* is dispatched. */
>             var otherParameters = {};
>             for ( var curPortletId in portlet.registry) {
>                 var eventData = {};
>                 eventData.eventType = 'actionParameters';
>                 eventData.portletId = portletId;
>                 otherParameters =
>                     otherParameters.concat(eventListener.call(null,
> eventData));
>                 broadcastEvent(portletId, eventData);
>             }

I have several questions about the actionParameters event.

I can see how this mechanism could be used by the portlet hub to collect
information from all portlets on the page. But what would happen to the
collected data? I assume it would be transported to the server in some
manner. Would it be packed into portlet parameters? Would it be added to
any form submitted as hidden fields?

How would the server deal with that data? How would the individual portlets
on the server receive the data, and what would they be expected to do with
it?

I understand that even when using server state saving, JSF stores at least
the ViewState in a hidden form field. The ViewState is needed when
performing an action or executing a portlet event on the JSF portlet or
when rendering a JSF portlet. So I can imagine that it would be useful to
collect the ViewState for all JSF portlets on the page and transport that
data to the server.

But one central idea behind portlets is that the portlet state is stored in
the portlet render parameters. The idea behind the portlet hub takes that
into account and manages the portlet state as reflected by the render
parameters such that the actual action URL used will contain the current
render parameters for all portlets on the page. if you consider a page of
native portlets (as opposed to JSF portlets), I don't really see what
additional data a native portlet would need to provide during an action
processing sequence that it does not initiate. Also, a native portlet would
have no mechanism for obtaining additional data provided in such a manner
unless new server-side methods are introduced.

So I can see utility in the idea for JSF portlets, but not for native
portlets. But if the utility of the recommendation is JSF-specific,
wouldn't it be more of a JSF Portlet Bridge issue rather than a portlet hub
issue?

Also, if the JSF ViewState is stored in a hidden form field, it must be a
serialized string. The JSF portlet bridge on the server could potentially
wrap the JSF portlet response and extract the view state. It could then
store the extracted ViewState as a private render parameter for the JSF
portlet (in addition to leaving it in the form as a hidden field). That
way, the ViewState for all JSF portlets on the page would automatically be
available through any action URL submitted without going through the
trouble of collecting the data from the individual portlets on the client
before the action is submitted. I believe that this approach would obviate
the need for an "actionParameters" event with its inherent complexity, need
for new Java APIs on the server, etc.

>
>             /* Send 'dispatchActionRequest' event to the portlet
> client that */
>             /* called this portlet.ajax.actionRequest function. Thatway
the */
>             /* portlet client has an opportunity to dispatch the
> request itself. */
>             var eventData = {};
>             eventData.eventType = 'dispatchActionRequest';
>             eventData.portletId = portletId;
>             eventData.url = actionURL;
>             eventData.parameters = otherParameters;
>             eventData.source = source;
>             broadcastEvent(portletId, eventData);
>         }
>     }
> }

I understand the need to do something like this in order to support JSF. I
don't really understand how the portlet hub can obtain the data it needs
while allowing the JSF Ajax module to execute the action. I think we need
further discussion here.

I understand that this event would only be fired for the specific portlet
that initiates the action processing rather than being sent to all portlets
on the page that are registered for the event. On more of a philosophical
note, this would be more of a classic callback function than an actual
event. If we go the route of allowing a Portlet Client to provide a
'dispatchActionRequest' function, it would seem to me to be better to
define it as a callback in order to reflect that reality. We might do so by
allowing an additional parameter on the action method, rather than having
the portlet client register an event.

I can see how a portlet client representing the JSF portlet bridge could
make good use of the callback. But how would it be for native portlets? If
we describe the method in the spec, we could not really forbid a general
native portlet from using it. And if a general native portlet client
decided to use it, correct functioning of the portlet hub and the portal
page as a whole would be dependent upon that portlet client providing the
state data back to the hub. I sort of have problems accepting that idea.

>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> 6. Replace the "onStateChange" callback with an "actionRequestComplete"
>     event that has the "portletState" and "renderData" supplied
> within "eventData".
>
> portlet.ajax = function() {
>     return {
>         actionResponse : function actionResponse(portletId, request) {
>             /* Send 'actionResponseComplete' event to the portlet client
*/
>             /* called this portlet.ajax.actionResponse function. */
>             var eventData = {};
>             eventData.eventType = 'actionRequestComplete';
>             eventData.portletId = portletId;
>             eventData.portletState = _GET_PORTLET_STATE(portletId,
request);
>             eventData.renderData = _GET_RENDER_DATA(portletId, request);
>             broadcastEvent(portletId, eventData);
>         }
>     }
> }

Once again, defining an event for "actionRequestComplete" implies to me a
contract that all subscribers to the event will be called when an action
completes. Thinking about the onStateChange method, that is not really the
case. The onStateChange method would only be called for the portlets whose
state have change, and each of those portlets would be passed
portlet-specific data.

Also, onStateChange can also be called when a portlet client calls the
setPortletState method, not only after an action.

>
>     NOTE that the portlet.ajax.actionResponse function would need tobe
called
>     from the portlet client when the asynchronous response comes back
from
>     the server. For example:
>
> var request = new XMLHttpRequest();
> request.onreadystatechange = function() {
>     if (request.readyState == 4 && request.status == 200) {
>         portlet.ajax.actionResponse(portletId, request);
>     }
> };

I don't really understand this point ... do you mean that the portlet
client executing the XHR would have to distribute the new portlet state and
possibly render data to the rest of the portlet clients?

>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> 7. Replace createResourceURL with "portlet.ajax.resourceRequest" and
>     have the "resourceURL" supplied within "eventData".
>
> portlet.ajax = function() {
>     return {
>         resourceRequest : function resourceRequest(portletId,
> source, resourceParams) {
>
>             /* Send 'dispatchResourceRequest' event to the portlet
> client that */
>             /* called this portlet.ajax.resourceRequest function. */
>             var eventData = {};
>             eventData.eventType = 'dispatchResourceRequest';
>             eventData.portletId = portletId;
>             eventData.url = _GET_RESOURCE_URL(portletId, resourceParams);
>             eventData.parameters = resourceParams;
>             eventData.source = source;
>             broadcastEvent(portletId, eventData);
>         }
>     }
> }

Somehow I don't really understand this ... sorry if I'm dense. Wouldn't
_GET_RESOURCE_URL() be the same thing as createResourceUrl()? Just as a
note, valid portal URLs cannot necessarily be "pieced together" by client
code. You might need a portal-specific method for generating them based on
the current page render state, resource parameters, and cacheability option
(which is the actual purpose of the proposed createResourceURL method).

How would the portlet hub know when a portlet client needs a new resource
URL? Based on a new portlet state, a portlet client might need to execute
0, 1, or several resource requests to obtain the necessary data for an
update.

>
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> 8. For consistency, broadcast "resourceRequestComplete" event as well.
>
> portlet.ajax = function() {
>     return {
>         resourceResponse : function resourceResponse(portletId, request)
{
>             /* Send 'resourceResponseComplete' event to the portlet
client */
>             /* called this portlet.ajax.resourceResponse function. */
>             var eventData = {};
>             eventData.eventType = 'resourceRequestComplete';
>             eventData.portletId = portletId;
>             eventData.portletState = _GET_PORTLET_STATE(portletId,
request);
>             eventData.renderData = _GET_RENDER_DATA(portletId, request);
>             broadcastEvent(portletId, eventData);
>         }
>     }
> }

But a resource request is portlet-specific. Why would we need to broadcast
its completion? What would we expect other portlets to do with that
information?

>
>     NOTE that the portlet.ajax.resourceResponse function would need
> to be called
>     from the portlet client when the asynchronous response comes back
from
>     the server. For example:
>
> var request = new XMLHttpRequest();
> request.onreadystatechange = function() {
>     if (request.readyState == 4 && request.status == 200) {
>         portlet.ajax.resourceResponse(portletId, request);
>     }
> };

Why would we want to impose this burden on the portlet client programmer?

If the portlet client can obtain a resource URL and execute a resource
request on its own, wouldn't that be sufficient?

>
> -- Neil
>
> [image removed]



[jsr362-experts:] Proposed changes to function names in the JavaScript API

Neil Griffin 04/08/2014

[jsr362-experts:] Re: Proposed changes to function names in the JavaScript API

Martin Scott Nicklous 04/10/2014
 
 
Close
loading
Please Confirm
Close