Action Component Developer's Guide


Table of Contents

Introduction
Action Component Portlet
Portlet Actions
Control
Portlet Mode Components
Action Component
Life Cycle
Portlet Requests
Action Events
Render Events
Action Methods
Action Links
Action Component Frame
Action Dialogs
Action Component Types
Developing Action Component Portlets

Introduction

Grid Portlets extends GridSphere's ActionPortlet with the ActionComponentPortlet. ActionComponentPortlet provides a more advanced model for developing and reusing user interfaces, called action components, represented by the ActionComponent class. This guide describes the action component model and how to develop new action components.

Action Component Portlet

ActionComponentPortlet is a portlet that contains "action components", represented by the ActionComponent class. Action components are reusable JSP user interface components that are contained within an action component frame, represented by the ActionComponentFrame class, where the top level action component frame is contained within ActionComponentPortlet. The top level action component frame displays the JSP of the active action component within that frame. Only one action component can be active within an action component frame. However, an action component can contain action component frames for displaying action components within its JSP. In this way, very sophisticated user interfaces can be built. In Grid Portlets, for example, FileBrowserComp contains two action component frames for displaying two instances of FileListComp side by side:


    <ui:table>
        <ui:tablerow>
            <!-- File browser 1 -->
            <ui:tablecell width="400" align="left" valign="top">
              <ui:text><b>File Browser 1</b></ui:text>
                <ui:group>
                <ui:actioncomponent beanId="fb1"/>
                </ui:group>
            </ui:tablecell>
            <!-- Transfer buttons -->
            <ui:tablecell align="center" valign="middle" width="50">
                <ui:table>
                    <ui:tablerow>
                        <ui:tablecell align="center" valign="middle">
                            <ui:actionsubmit action="doCopyFilesFb1Fb2" value="Copy >>"/>
                            <br>
                            <ui:actionsubmit action="doMoveFilesFb1Fb2" value="Move >>"/>
                            <br>
                        </ui:tablecell>
                    </ui:tablerow>
                    <ui:tablerow>
                        <ui:tablecell align="center" valign="middle">
                            <br>
                            <ui:actionsubmit action="doCopyFilesFb2Fb1" value="<< Copy"/>
                            <br>
                            <ui:actionsubmit action="doMoveFilesFb2Fb1" value="<< Move"/>
                        </ui:tablecell>
                    </ui:tablerow>
                </ui:table>
            </ui:tablecell>
            <!-- File browser 2 -->
            <ui:tablecell align="left" valign="top">
                <ui:text><b>File Browser 2</b></ui:text>
                <ui:group>
                <ui:actioncomponent beanId="fb2"/>
                </ui:group>
            </ui:tablecell>
        </ui:tablerow>
    </ui:table>

            

resulting in the following HTML:

                

Portlet Actions

Like ActionPortlet in GridSphere, ActionComponentPortlet provides a natural way to deal with portlet actions. Each action component is assigned a unique component id. When an action component is rendered, the bean id for all tag beans that are contained within the action component are prefixed with this unique component id. The result is that each input field in the rendered HTML is uniquely identified, associated with the action component they originate from by this component id prefix. This is discussed in more detail in the Action Component section below.

Since each action component has its own scope within JSP and the rendered HTML, there is no need to specify form tags within JSP (except when file input forms are required). Instead, ActionComponentPortlet renders one form tag at the top level. When a user clicks on an action submit button or action link, the current values of the input fields in the rendered HTML are applied to the corresponding tag beans of all the action components currently displayed. Then the resulting portlet action is mapped to a method on the action component class and this method is invoked. For all other action components displayed in the HTML, the doRender method is invoked. By default, this means the current values of the action component will simply be displayed. This process is described in more detail in the Action Component Life Cycle section.

Control

Like ActionPortlet in GridSphere, ActionComponentPortlet provides a natural way for dealing with control, through the setNextState method of ActionComponent. By default, an action component will set the next state of its parent action component frame to its defalt jsp page after its action method is invoked. However, this can be overridden inside the body of an action method. An action component can set the next state of its parent frame to an action method of another action component. That action component then becomes the active component within the parent frame, and so on, until the state the parent frame is set to a jsp page to display. Action components can also pass control up to the action component frame with by specifying action links, described in more detail later in this guide.

Portlet Mode Components

When an action component portlet is constructed for the first time, it registers the appropriate default action component to load for each portlet mode. In Grid Portlets, for example, FileBrowserPortlet, sets its portlet VIEW mode default action component to FileBrowserComp. Thus, when FileBrowserPortlet is viewed for the first time in a user session, it sets the next state of its top level action component frame to the default action method of FileBrowserComp.

    
    public class FileBrowserPortlet extends ActionComponentPortlet {

        private transient static PortletLog log = SportletLog.getInstance(FileBrowserPortlet.class);

        public void init(PortletConfig config) throws PortletException {
            super.init(config);
            setViewModeComp(FileBrowserComp.class);
        }
    }
    
            

Action Component

Action components are objects that are responsbile for generating some JSP to display within the context of an action component portlet. Action components have a default action method, a render action method (set to null by default), and a default jsp page to display after any action method invoked. Action components can contain tag beans which are arragned for display in JSP. Among these tag beans, an action component can contain action component frames for displaying action components within its JSP.

Action components are created with ActionComponentFactory, a portlet service that gets deployed with each web application. Because, action components are JSP based, and because JSP files are only accessible within a particular servlet context, an ActionComponentFactory is deployed with each web application, where it can use the servlet context to get access to the web files and action component classes deployed with the web application.

Grid Portlets registers action components and to which web application they belong with /WEB-INF/ActionComponentTypes.xml, located in each web application. This file contains action-component-type entries, which specify an application component class and other properties associated with that class, such as what its default action method is, its default jsp file, and so on. These entries get marshaled into an ActionComponentType. Each web application ActionComponentFactory then registers these types with the Grid Portlets ActionComponentFactory at startup, which acts as a sort of broker for instantiating all the action component classes.

Life Cycle

An action component is created only once per action component frame per user session, with the ActionComponent(ActionComponentFrame frame, String compId) method. The constructor method is where creation of tag beans usually occurs, illustrated in examples later in this guide. Also, in the constructor the default action method, render action method, and jsp page can be set, though it is generally best to specify these attributes in the action component type entries in /WEB-INF/ActionComponentTypes.xml.

`

Portlet Requests

An action component portlet contains a tree of action component frames and components. When ActionComponentPortlet processes a portlet request, it retrieves its top level action component for the current user session. If the portlet request does not contain an action, then the top level frame retrieves its active component and calls its doRender method. doRender will invoke the active component's default action if this is the first time it is being displayed. If the component has been displayed before, then it calls its render action method if it is not null, otherwise it will display the appropriate jsp page.

If the portlet request contains an action, then a check is performed to see if the action string is mapped to the action method of an action component other than the active component (see Action Links below). If not, it checks to see if the action string maps to a method on the active component or to the method of an action component contained at a deeper level in the tree.

The action string represents a nested level of calls like so:


<actionPortletId>%actionCompFrameId>%<actionCompId>%[<actionMethod>|%<actionCompFrameId>%<actionCompId>%[...]]

            

Thus, if the action string maps to a method on the active component, it invokes that components doAction. Otherwise, it passes the action string onto the doAction of the action component frame referred to in the string. Finally, the doRender method of all the other action component frames contained in the active component contains is called, which results the doRender of its active component and so on. This logic is repeated until the action string bottoms out to a final method call. How actions map to methods on action components is discussed in more detail in the Action Methods section below.

`

Action Events

When doAction(String action, Map parameters) on ActionComponentFrame is called, the following events occur:

  1. The active component is retrieved.

    The active action component for the action component frame is retrieved from ActionComponentFactory.

  2. The active component is "initialized".

    The onInit() method is invoked each time an instance of an action component is retrieved from ActionComponentFactory. Override this method whenever additional initialization is needed, such as getting handles to portlet services.

  3. The active component is "loaded" from the request.

    The onLoad() method is invoked after an action component has been loaded from a request. This will update the values of the tab beans contained in the action component with the values of input fields retreived from the portlet request through its request paraemters. Override this method whenever some additional preprocessing is necessary before the action invokation phase. For example, if a value from the request should be translated to another value or handled in some particular way for every action, then that logic should be performed here.

  4. The action string is handled.

    The action string is handled in the manner described earlier.

  5. The active component is "stored" to the request.

    The onStore() method is invoked after an action component has been stored to a request. Override this method whenever some additional postprocessing is necessary after the action method phase. For example, if some value should be stored to the request so that it is available in JSP for every action method, it is best to put that logic here.

`

Render Events

When doRender on ActionComponentFrame is called, the following events occur:

  1. The active action component is retrieved.

    The active action component is retrieved from ActionComponentFactory.

  2. The active component is "initialized".

    The onInit() method is invoked each time an instance of an action component is retrieved from ActionComponentFactory. Override this method whenever additional initialization is needed, such as getting handles to portlet services.

  3. The active component is "loaded" from the request.

    The onLoad() method is invoked after an action component has been loaded from a request. This will update the values of the tab beans contained in the action component with the values of input fields retreived from the portlet request through its request paraemters. Override this method whenever some additional preprocessing is necessary before the action invokation phase. For example, if a value from the request should be translated to another value or handled in some particular way for every action, then that logic should be performed here.

  4. The active component is "rendered".

    doRender(String action, Map parameters) on the active component is called.

  5. The active component is "stored" to the request.

    The onStore() method is invoked after an action component has been stored to a request. Override this method whenever some additional postprocessing is necessary after the action method phase. For example, if some value should be stored to the request so that it is available in JSP for every action method, it is best to put that logic here.

Action Methods

In the action component model, portlet actions originating from an action submit button or an action link get mapped to methods on the corresponding action component class. These actions take the form:

    <actionMethodName>(Map parameters)
            
where the parameters argument contains the action parameters that were specified in the action. For example, if in JSP we have an action link tag:
                
    <ui:actionlink action="doMyAction1" value="An Action Link">
        <ui:actionparam name="actionParam1" value="actionValue1"/>
        <ui:actionparam name="actionParam2" value="actionValue2"/>
    </ui:actionlink>
                
            
then when a user clicks on the hyperlink displayed by the action link tag, the action will be mapped to:
    doMyAction1(Map parameters)
            
on the corresponding action component, and the parameters specified above will be accessible in the parameters argument:
                
    String actionParam1 = parameters.get("actionParam1");
    String actionParam2 = parameters.get("actionParam2");
                
            

Similarly, if in JSP we have an action submit tag:

            
<ui:actionsubmit action="doMyAction2" value="An Action Link">
    <ui:actionparam name="actionParam1" value="actionValue1"/>
    <ui:actionparam name="actionParam2" value="actionValue2"/>
</ui:actionsubmit>
            
        
which displays a button, then when a user clicks on that button the action will be mapped to:
doMyAction2(Map parameters)
        
on the corresponding action component, and the parameters specified above will be accessible in the parameters argument.

Action Links

Action components can map portlet strings to the action methods of other other components. This is achieved with the registerActionLink method. This method is used to map an action received by one component to that of another. This is useful, in particular, with the ui:actionlink tag and it is not necessary to handle the action in the active component.

Let's say you display a list of items in a table with an action component called ListItemsComp and when a user selects one of those items to view, you want to view the item with ViewItemComp. So, in the JSP for ListItemsComp you might have:

    
    <% List itemList = ActionComponent.getPageAttribute(request, "itemList", new ArrayList());
       Iterator itemIter = itemList.iterator(); %>
    <ui:table>
        <ui:tr header="true">
            <ui:td>
                <ui:text value="ID"/>
            <ui:td>
            <ui:td>
                <ui:text value="Attribute 1"/>
            <ui:td>
            <ui:td>
                <ui:text value="Attribute 2"/>
            <ui:td>
        </ui:tr>
        <% while (itemIter.hasNext()) { %>
               MyItem item = (MyItem)itemIter.next();
               String itemId = item.getId();
               String attribute1 = item.getAttribute1();
               String attribute2 = item.getAttribute2(); %>
        <ui:tr>
            <ui:td>
                <ui:actionlink action="doViewItem" value="<%=itemId%>">
                    <ui:actionparam name="itemId" value="<%=itemId%>"/>
                </ui:actionlink>
            <ui:td>
            <ui:td>
                <ui:text value="<%=attribute1%>"/>
            <ui:td>
            <ui:td>
                <ui:text value="<%=attribute2%>"/>
            <ui:td>
        </ui:tr>
        <% } %>
    </ui:table>
    
            

In ListItemsComp you would setup an action link for the doViewItem action like so:

                
public class ListItemsComp extends ActionComponent {

    // Other member variables...

    public ListItemsComp(ActionComponentFrame container, String compName)
            throws PortletException {
        // Call our super method...
        super(container, compName);

        // Register our action link. Forwards "doViewItem" method to ViewItemComp
        registerActionLink(getClass(), "doViewItem", ViewItemComp.class);

        // More code...
    }
                
            

Now, the parent frame to ListItemsComp will know to invoke the "doViewItem" method on ViewItemComp when ListItemsComp is the active component and it receives an action string with "doViewItem" as the value.

Action Component Frame

As discussed earlier, action components can contain other action components within action component frames. An initial state for each child action component frame can be set in the constructor method or the onInit method of each action component. In the FileBrowserComp, for example, we contain two instances of FileListComp like so:

                
public class FileBrowserComp extends FileComp {

    // Other member variables...

    // Frame for file "browser" 1
    protected ActionComponentFrame fileBrowser1Bean = null;
    // Frame for file "browser" 2
    protected ActionComponentFrame fileBrowser2Bean = null;

    // Other member variables...

    public FileBrowserComp(ActionComponentFrame container, String compName)
            throws PortletException {
        // Call our super method...
        super(container, compName);

        // File browser 1
        fileBrowser1Bean = createActionComponentFrame("fb1");
        fileBrowser1Bean.setNextState(FileListComp.class, DEFAULT_ACTION);

        // File browser 2
        fileBrowser2Bean = createActionComponentFrame("fb2");
        fileBrowser2Bean.setNextState(FileListComp.class, DEFAULT_ACTION);

        // More code...

        // Default jsp page
        setDefaultJspPage("/jsp/file/FileBrowserComp.jsp");
    }
                
            

GridSphere provides an action component tag for displaying action component frames in JSP. So, in order to display file browser 1 for the code above, in the JSP file /jsp/file/FileBrowserComp.jsp we use the action component tag like so:

                    
    <ui:actioncomponent beanId="fb1"/>
                    
                 

Action Dialogs

Action dialogs are modal components, components that assume control of the top level action component frame. They are created with the getActionDialog method of ActionComponent. Once opened with showOkCancelDialog, for example, they remain the active component in the top-level action component frame until either the doOk method of the action dialog is called and it results in the closeDialog being called, or the doCancel is called. In both cases, the action component that creates the dialog must specify the next state to forward control to once the dialog closes. This is best illustrated with an example.

FileListComp will open a FileMakeDirDialog when its doMakeDir action method like so:

                
    FileMakeDirDialog dialog
            = (FileMakeDirDialog)getActionDialog(FileMakeDirDialog.class);
    dialog.setFileHost(fileHostName);
    dialog.setFilePath(currentPathField.getValue());
    dialog.setMessageValue(getResourceString(MAKEDIR_MESSAGE_KEY));
    dialog.showOkCancelDialog(new ActionComponentState(getClass(), "doMakeDirApply"),
                              new ActionComponentState(getClass(), RENDER_ACTION));
                
            
FileListComp specifies to invoke to its doMakeDir method when the user clicks on "OK" on the the file make dir dialog and to invoke its render action when the user clicks cancel instead.

Action Component Types

Action components are registed with /WEB-INF/ActionComponentTypes.xml inside each web application. This file contains multiple action-component-type entries which describe the action components contained in each web application.

        
        <action-component-types>

            <action-component-type
                classname="YourActionComponentClass"
                default-action="TheFirstActionToPerform"
                render-action="AnActionToPerformInDoRender"
                default-jsp="TheDefeaultJspPageToDisplay"/>

            <!-- Specify as many action-component-type entries as you want -->

        </action-component-types>
        
            

Developing Action Component Portlets

Developing an action component portlet amounts to extending ActionComponentPortlet and extending ActionComponent for each action component you wish to develop. Once the necessary classes have been implemented, then you specify your portlet entry in /WEB-INF/portlet.xml and your action components in /WEB-INF/ActionComponentTypes.xml. The required steps are summarized below:

  1. Create a Grid portlet project. Grid Portlets offers two ant targets for doing so:

    1. To create a new project from scratch, run ant new-project and follow its instructions. This is similar to the new-project target in GridSphere. It will create a new portlet project in the projects directory of GridSphere that includes support for developing new action components.

    2. To modify an existing portlet project to support development of action components and job profiles, run ant update-project and follow its instructions. This is similar to the update-project target in GridSphere. It will update an existing portlet project in the projects directory of GridSphere with the latest project files from GridSpehre and Grid Portlets.

  2. Implement your action components, extending from ActionComponent.

  3. Specify the action component classes you developed in /WEB-INF/ActionComponentTypes.xml.

  4. Extend ActionComponentPortlet. Inside the init method of your portlet, set the default action components to display for each portlet mode your portlet supports:

                
    public class MyComponentPortlet extends ActionComponentPortlet {
    
        public void init(PortletConfig config) throws PortletException {
            super.init(config);
            setViewModeComp(MyViewModeComp.class);
            setEditModeComp(MyEditModeComp.class);
            setHelpModeComp(MyHelpModeComp.class);
        }
    }
                
                    

  5. Specify the portlet you developed in /WEB-INF/portlet.xml.

Once you've completed your work, simply redeploy your web application and restart your webserver if necessary.