Samples > Sample stores > Consumer direct sample store > IBM Gift Center for the Consumer direct sample store > IBM Gift Center > Customize the Web (presentation) layer


Chain Struts actions and commands

You may need to create new wrapper actions that accomplish two tasks in a row, while reusing the actions or controller commands that are already implemented.

For example, the UserGiftRegistryCreate action...

  1. Registers a new user
  2. Creates a gift registry in the name of the newly created user

Since both UserRegistrationAdd and GiftRegistryCreate are implemented, you can reuse the implementation, and therefore, chain different Struts actions and controller commands into a single Struts action. The new action that does the chaining is considered the host action.

To invoke a controller command...

getWebAdapter().executeCommand(getCommandContext(request), inMap, YourControllCommand.class.getName())

...where...

getWebAdapter() returns an instance of WebAdapterServiceAccessBean
getCommandContext(request) retrieves the command context in use from an HTTP request
YourControllCommand interface name of the command to be invoked

As a reference implementation, getAdapter() is really a one-liner:

private WebAdapterServiceAccessBean getWebAdapter() { return new WebAdapterServiceAccessBean(); }
Likewise, getCommandContext() is also simple:

private CommandContext getCommandContext(HttpServletRequest request) 
{ 
    return ((RequestHandle) request.getAttribute(ECAttributes.ATTR_EC_REQUEST_HANDLE)).getViewCommandContext(); 
}  

The execution of...

getWebAdapter().executeCommand(getCommandContext(request), inMap, YouControllCommand.class.getName())

...returns the response object returned by the executed command.

Invoking another IBM Gift Center Struts action is more complex. Struts actions and action forms use action names to resolve the name of the service that will be invoked, and the service mapping group that determines how incoming request name-value pairs should be mapped to a BOD object.

The action name is stored in the ActionMapping object used by the host action. Therefore, change the action name right before the chained action that is being called. Otherwise, the service mapper will not be able to find the correct mappings. For example, the Struts action UserGiftRegistryCreate chains another action, called GiftRegistryCreate. Without any change, the action name will be UserGiftRegistryCreate even if GiftRegistryCreate is being invoked. Then, GiftRegistryCreate will not be able to retrieve the mapping it expects because all the expected mappings are bound to its name, GiftRegistryCreate.

You can resolve this problem using following steps:

  1. Associate the host action with GiftRegistryActionMapping. This action mapping provides a new property: actionPaths. Specify comma-delimited action names. For example, to invoke GiftRegistryCreate from UserGiftRegistryCreate, specify

    <set-property property="actionPaths" 
                     value="/GiftRegistryCreate"/>.
    

    The following is the complete configuration for UserGiftRegistryCreate:

    <action parameter="com.ibm.commerce.giftregistry.commands.UserGiftRegistryCreateCmd"
            name="UserGiftRegistryCreateActionForm" 
            path="/UserGiftRegistryCreate" 
            type="com.ibm.commerce.giftregistry.struts.UserGiftRegistryCreateAction" 
            validate="false">     
        
        <set-property property="https" value="0:1"/>     
        
        <!-- 
        This property indicates that UserGiftRegistryCreate 
        will invoke the action GiftRegistryCreate 
        -->     
        
        <set-property property="actionPaths" value="/GiftRegistryCreate"/>
    
    </action>
    

  2. To invoke a chained action, invoke super.invokeService(getMappingForNewActions(mapping), form, inMap, request, response), where getMappingForNewActions() is implemented as follows (assuming that only one action is to be invoked):

    private ECActionMapping getMappingForNewActions(ActionMapping mapping) 
    {
        ECActionMapping newMapping = new ECActionMapping(); 
        newMapping.merge(mapping);     
        newMapping.setPath(((GiftRegistryActionMapping) mapping).getActionPaths()); 
        return newMapping; 
    }
    

    The snippet first creates a new action mapping, and then duplicates the content of the current action mapping into the new mapping. As an ActionMapping instance is a singleton per action, you do not want to permanently change it. The new mapping uses the specified action path as the new action name. Since this new action mapping will be passed into the invokeService() subsquently, the service mapper will use the mapping information bound to the action name in this new mapping. Therefore, the chained action will be invoked properly.

    Sometimes, a transaction will be committed after a controller command is executed.

    To roll back the transaction in the host action, use WebControllerHelper.rollbackService(GiftRegistryUtils.getActivityToken()), where GiftRegistryUtils.getActivityToken() returns the activity token used in the current transaction.


Related concepts

IBM Gift Center architecture


Related tasks

Customize the component and data service layers


+

Search Tips   |   Advanced Search