Glenn, 

> David -
> 
> Just wondering, are you going to dig through the large email 
> I sent re: using turbine actions and state for portlets?  Or 
> is it too large, undigestable!

Did you mean to send this to my personal email account? <:-)
Well, considering it was almost 5 pages, yes, Im still trying to dig
thru it.

May I counter with, have you had a chance to review the DatabaseBrowser
code, and how it handles state?
I limited all the state management to within the action, but I could see
most of that code going into a generic state management service. 

Should I send your email and my responses to the list so that we can
continue the discussion here?

David

> -----Original Message-----
> From: Glenn Golden [mailto:[EMAIL PROTECTED]] 
> Sent: Friday, April 12, 2002 8:24 AM
> To: 'Jetspeed Developers List'
> Subject: Just wondering...
> 
> 
> David -
> 
> Just wondering, are you going to dig through the large email 
> I sent re: using turbine actions and state for portlets?  Or 
> is it too large, undigestable!
> 
> If the later, I can raise some points that were in there 
> individually for discussion, such as the one at the very end 
> about the velocity context...
> 
> Thanks.
> 
> - Glenn
>  
> --------------------------------------------
> Glenn R. Golden, Systems Research Programmer
> University of Michigan School of Information
> [EMAIL PROTECTED]               734-615-1419
> --------------------------------------------
> 
> 
> Here's the big one:
> 
> David -
> 
> Let me try again with this; from your response, I'm not 
> feeling that I've communicated this clearly, and I think this 
> might be a wonderful idea, and I really want your ideas on this...
> 
> Consider that we are writing a "portlet" that creates 
> different output based on many things:
> - how it's configured (registry)
> - how it's customized (psml parameters)
> - what the user has done so far (our new portlet instance 
> state) (and of course some sort of "model" from a db or 
> service behind the scenes).
> 
> There are various html forms that this portlet will produce 
> for the user, with various buttons the user will press to 
> send data back to the portlet. We want to use the actionEvent 
> model of "doWhatever()" methods in our "portlet" to handle 
> each different button press.
> 
> That's how input processing is handled; output processing is 
> handled by another method in our "portlet" class, something 
> like getContent() to produce our html, or 
> buildNormalContext() to setup our velocity context and choose 
> our velocity template.
> 
> So far, we have entry points in the "portlet" for input 
> processing, entry points in the "portlet" for output 
> preparation, all in one "portlet" class. Nice, yes?
> 
> Now, I'm "quoting" "portlet" because there's a difference 
> between the portlet api portlet and the object model portlet, 
> and I'm not sure which I mean here.  The object model portlet 
> is what identifies that there is a portlet instance in a 
> portal page, and carries the configuration and customization 
> information for that instance.
> 
> The portlet api portlet is what is called upon at runtime to 
> handle requests.
> 
> Granted that we want a better distinction between these two, 
> and stronger lines, and clearer ideas of when which is used 
> and who is responsible for what...
> 
> But for this email, what we need in our "portlet" is the 
> information from customization, configuration, and portlet 
> instance state, and to be called upon at the appropriate time 
> to handle our input and produce our output.
> 
> What sort of object would this be?
> 
> To work with the Turbine ActionEvent model, our "portlet" 
> would need to encode "action=OurNameHere" in the form action 
> URL or form fields of our html.  And we would have to extend 
> ActionEvent from Turbine.  And we would have to use 
> "eventSubmit_doWhatever" for button names, matching our 
> "doWhatever()" methods.
> 
> Then, when the user hits our button, our "portlet" object is 
> constructed and called as a real turbine action.  Call to 
> *ONLY* process the form input.
> 
> We process the form input, make changes to the portlet 
> instance state, and that's all for now.  (Stand by, Turbine 
> is about to aggregate the page and we will be called again to 
> provide our current content).
> 
> But, alas, how do we get at the information (configuration, 
> customization,
> state) that we need to process the input, and how do we 
> modify information (state only) based on this input?
> 
> We are so clever - we encode a unique key into our forms, use 
> that key with a clever new state manager service to gain 
> access to the state for the portlet instance.  If we need to 
> get at customization and configuration (i.e. om aspects of 
> the portlet instance), I imagine that that key is all we need 
> to find this information (it uniquely id's the portal page 
> and portlet element).  Or, we have cleverly filled our 
> portlet instance state with whatever we need to process our 
> form input.
> 
> So, see how we use state to process inputs?
> 
> Now, we are done processing out inputs, we have read the form 
> parameters and modified the state that is keyed by the key 
> from the form.  Wait - is our code the proper code to handle 
> this request?  Sure - the "action=us" in the request picked 
> us.  And did we modify the correct state? Sure - the state 
> key in the request identified that.  And how do we know that 
> there was state already waiting with this key?  Because the 
> very first thing that happens to a portlet instance is that 
> it is called upon to produce html, getContent() or 
> buildNormalContext(), and we wrote that routine and made sure 
> that it initialized a state object, wrote the proper form 
> with the proper key, etc.
> 
> Ok, on with the show.
> 
> Turbine, after the "action=" processing, processes the 
> screen, and that kicks off the Jetspeed aggregator, which, 
> based on the OM portal page definition, picks the appropriate 
> portlet objects to produce output, and gives aspects of the 
> OM information (configuration and customization) to the 
> portlet class to work with (maybe not as we would like, 
> portletConfig and all, but for now we live with it).  Thus, 
> our code is not only an ActionEvent, but a Portlet, too!  So, 
> we get another call, and have all our Portlet information 
> available, and we can make our key (based on our id and our 
> portal page's id), and get our state as well, and we are, as 
> they say, Golden.
> 
> What just happened?  We have a way to write portlets and 
> process the responses so only the intended "portlet" (portlet 
> instance) gets the response.  We don't have to worry about 
> form name conflicts in the aggregate of ours and unknown 
> other portlets.  If we have two instances on the same page, 
> the key keeps us separate (which is what I propose we want, 
> separateness).
> 
> Can we do this now?
> 
> For VelocityPortlets, it's easy.  When we do velocity 
> portlets, we never write Portlet API code, we just write 
> Action classes.  We just have to write them in the way 
> described, with our do() routines and our
> buildNormalContext() routines.  We don't have to also be a 
> "Portlet" for aggregation.  VelocityPortlet recignizes the 
> case where there was an action in the request and then skips 
> its own version of action processing, calling only 
> buildNormalContext() for all portlets.
> 
> For Portlet portlets, I think we can make a new abstract 
> portlet that extends ActionEvent and implements Portlet, so 
> we get do() routines and getContent().  We'd have to figure 
> out how this works with the wrappers, but it looks possible.
> 
> Here's an example of a velocity portlet action class that is 
> coded in this way, using the proposed state manager.  The 
> state is just an integer and a message.  When the user 
> presses "next", the state int ++, and when the user presses 
> "prev", the state int --.  The message remembers which the 
> user last pressed. (Warning: may not compile, I cut out some 
> stuff for this example):
> 
> public class TestAction
>     extends VelocityPortletAction
> {
>     // context processing ONLY
>     protected void buildNormalContext(  VelocityPortlet portlet, 
>                                         Context context,
>                                         RunData rundata )
>     {
>         // find our state
>         Integer state = (Integer) portlet.getState("state", rundata);
>         if (state == null)
>         {
>             // construct our state
>             state = new Integer(0);
>             portlet.setState("state", state, rundata);
>         }
>         
>         // combine some configuration/customization with 
> state # for the message
>         context.put("message", 
>             portlet.getPortletConfig().getInitParameter("message")
>             + " state: " + state.toString());
>         context.put("state", portlet.getStateKey(rundata));
>         String stateMsg = (String) 
> portlet.getState("message", rundata);
>         if (stateMsg != null) context.put("state-msg", stateMsg);
> 
>         // do this and the action will be processed in 
> turbine action space
>         context.put("action", "TestAction");
> 
>         context.put("formAction", new DynamicURI(rundata).toString());
>         context.put("doPrev", BUTTON + "doPrev");
>         context.put("doNext", BUTTON + "doNext");
>         context.put("stateKey", "state");
> 
>     }   // buildNormalContext
> 
>     /**
>     * doNext called for form input tags type="submit" 
> named="eventSubmit_doNext"
>     * input processing only!
>     */
>     public void doNext(RunData data, Context context)
>     {
>         // which portlet instance state key 
>         String key = data.getParameters().getString("state");
> 
>         // get the state from the manager
>         StateManagerService mgr =
> (StateManagerService)TurbineServices.getInstance()
>                 .getService(StateManagerService.SERVICE_NAME);
>         Integer state = (Integer) mgr.getState(key, "state");
>         mgr.setState(key, "state", new Integer(state.intValue() + 1));
>         mgr.setState(key, "message", "from next");
> 
>     }   // doNext
> 
>     /**
>     * doPrev called for form input tags type="submit" 
> named="eventSubmit_doPrev"
>     * input processing only!
>     */
>     public void doPrev(RunData data, Context context)
>     {
>         // which portlet instance state key 
>         String key = data.getParameters().getString("state");
> 
>         // get the state from the manager
>         StateManagerService mgr =
> (StateManagerService)TurbineServices.getInstance()
>                 .getService(StateManagerService.SERVICE_NAME);
>         Integer state = (Integer) mgr.getState(key, "state");
>         mgr.setState(key, "state", new Integer(state.intValue() - 1));
>         mgr.setState(key, "message", "from prev");
> 
>     }   // doPrev
> 
> }   // TestAction
> 
> 
> Here's the .vm:
> 
> ## a form to send to my actions
> <form action="$formAction" method="post">
>     #if ($state-msg) <h2>$message $state-msg</h2> #end
>     <input type="hidden" name="action" value="$action" />
>     <input type="hidden" name="$stateKey" value="$state" />
>     <input type="submit" name="$doPrev" value="<-- prev" />
>     <input type="submit" name="$doNext" value="next -->" /> </form>
> 
> * * * * * * * * * * * * *
> 
> So, thanks for staying with me so far!  Portlet instance 
> state lets us do this neat separation.  Unique ids help, too. 
>  I think this is perfect for input processing, proper portlet 
> (and instance) targeting, and output processing.  To be real 
> clean, I'd in my first getContent() or
> buildNormalContext() pull any info about the configuration / 
> customization that I'd need for action do() routines and 
> place it in my state, so it's easily available when my forms 
> come back.
> 
> The only problem left, and it's a biggy, is the name space 
> conflict in the context.  If we do lots of portlets this way, 
> we will likely all be placeing "$action" with out class name 
> and "$state" with our state key and ... Why does the context 
> need to be kept from one portlet aggregation to the next? 
> Can't we setup the context, run the template, then clear the 
> context and go to the next portlet?  That would take care of 
> that little problem.
> 
> So, have I made my case?
> 
> Thanks so much!
> 
> - Glenn
> 
> 
> 
> --
> To unsubscribe, e-mail:   
> <mailto:jetspeed-dev-> [EMAIL PROTECTED]>
> For 
> additional commands, 
> e-mail: <mailto:[EMAIL PROTECTED]>
> 
> 



--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to