Changes to configuration files
Struts Portlet Framework specific init parameters have been added that allows you to customize the Struts application for the portal environment. The portlet and web deployment descriptors require configurations specific to the Struts Portlet Framework. In addition, changes to the Struts configuration file must be made to specify a portal specific request processor as the controller.
- Configuring the Struts application for the IBM container
- Configuring the Struts application for the standard portlet container
- Setting an initial view
- Using modes
- Support for devices
- Internationalization support
- WML support
- Logging
- Changes to the Struts configuration file
- Tiles support
Configuring the Struts application for the IBM container
<servlet id="Servlet_1">
<servlet-name>MyStrutsApp</servlet-name>
<servlet-class>com.ibm.wps.portlets.struts.WpsStrutsPortlet
</servlet-class>
...
</servlet>
When sub-classing WpsStrutsPortlet, you should designate the subclass name for <servlet-name/>. The servlet id should be suffixed with a unique ID to prevent conflicts with other portlets. See Deployment descriptors for more information.
- Initialization parameters
- The following is a list of names of the initialization parameters
that can be configured in the web deployment descriptor for Struts
portlets (using the <init-param> element).
- CommandManagerPlugin
- This configuration parameter will allow setting a pluggable CommandManager
- struts-servlet-mapping
- Identifies a Struts action mapping so that paths that should be treated as Struts actions can be recognized. See Servlet mapping for further details.
- ModuleSearchPath
- Indicates the search path for Struts modules, default value is the markupName and mode. See Using modes for more information.
- IncludesSearchPath
- Indicates a more fine-tuned search path for including a file. If this value is not specified then PortletContext.include() is used instead.
- NamescopeServletContext
- This allows the WpsStrutsPortlet to be defined in the web deployment descriptor more than once by namescoping the parameters in the servlet context.
- NamescopeFormName
- The default behavior is for the Struts form tag to namescope the name of the portlet. Setting this parameter to false will allow the behavior to be overridden.
- UseGroupsForAccess
- Configures the Struts portlet to use portal server group names as if they were role names. Struts uses roles to determine access to an Action. Set this parameter to true to configure the Struts application to use the portal's group names as if they were role names to emulate role-based access control.
- UsePortalsLocale
- This parameter will allow a Struts application to override default behavior of using the portal's locale. If this parameter is set to false the Struts application can use the Request Processor's processLocale method for controlling locale or set the locale in a Struts action; otherwise, it uses the portal's locale and also supports dynamic changes. The default value is true.
- WelcomeFileSearchPath
- This configuration parameter will allow customizing the initial view page search.
- Servlet mapping
- In a portlet, you need to use a servlet URL mapping for your portlet.
So, one would typically use a path prefix servlet mapping similar
to the following.
<servlet-mapping id="ServletMapping_1"> <servlet-name>MyStrutsApp</servlet-name> <url-pattern>/Struts/*</url-pattern> </servlet-mapping>The typical Struts application uses an extension mapping. The Struts example uses extension mapping and it is expected that most Struts applications use the extension mapping "*.do". In the normal Struts case, this means that URIs ending in "*.do" are directed to the Struts servlet. Remember that Struts provides a single servlet that you can use (or subclass) for all of your Struts applications. When you want to cause control to be given to a Struts Action when a link is selected or form submitted, use the extension from the extension mapping (e.g. "*.do") on the URI so that the processing is routed to the Struts ActionServlet. Other URIs, such as those for JSPs, do not have this extension and, thus, would not be routed through the Action Servlet for processing.
A Struts application, which is itself a servlet application, also requires a servlet mapping. Although our Struts portlet already has a servlet mapping as shown previously, you still need to identify what to use as a Struts action mapping so that paths that should be treated as Struts actions can be recognized. To specify the pseudo servlet mapping used by Struts, specify it as a servlet initialization parameter in the web.xml file, as follows:<init-param> <param-name>struts-servlet-mapping</param-name> <param-value>*.do</param-value> </init-param>The Struts Portlet Framework supports the same servlet mappings modes as the servlet-based Struts application. However, the current Struts implementation only supports extension mapping for the module implementation. Since the portal server implementation uses modules for the mode and markup support, it is strongly recommended that the extension mapping is used.
Configuring the Struts application for the standard portlet container
<portlet>
<portlet-class>com.ibm.portal.struts.portlet.StrutsPortlet</portlet-class>
</portlet>
If sub-classing the StrutsPortlet, the subclass class name should be designated as the <portlet-class/>.
Initialization parameters
- IncludesSearchPath
- Indicates a more fine-tuned search path for including a file. If this value is not specified then PortletContext.include() is used instead.
- ModuleSearchPath
- Indicates the search path for Struts modules, default value is the markupName and mode. See Support for multiple Struts applications for more information
- NamescopeFormName
- The default behavior is for the Struts form tag to namescope the name of the portlet. Setting this parameter to false will allow the behavior to be overridden.
- NamescopeServletContext
- This allows the WpsStrutsPortlet to be defined in the web deployment descriptor more than once by namescoping the parameters in the servlet context.
- struts-servlet-mapping
- Identifies a Struts action mapping so that paths that should be treated as Struts actions can be recognized. See Servlet mapping for further details.
- UseGroupsForAccess
- Configures the Struts portlet to use portal server group names as if they were role names. Struts uses roles to determine access to an Action. However, WebSphere Portal V 4.2 does not support roles. Set this parameter to true to configure the Struts application to use the portal's group names as if they were role names to emulate role-based access control.
- UsePortalsLocale
- This parameter will allow a Struts application to override default behavior of using the portal's locale. If this parameter is set to false, the Struts application can use the Request Processor's processLocale method for controlling locale or set the locale in a Struts action. Otherwise, it uses the portal's locale and also supports dynamic changes. The default value is true.
- WelcomeFileSearchPath
- This configuration parameter will allow customizing the initial view page search.
Setting an initial view
The Struts application needs to specify what the initial view is for the application. The typical way that the initial screen is specified is through the welcome file list. The Struts Portlet Framework supports the welcome file list configuration, and has some additional features. The servlet implementation of the welcome file list only supports JSP and HTML pages. The Struts Portlet Framework supports a JSP or HTML welcome file, and also allows a Struts action to be specified as the welcome file. See Example 1 for implementation details.
The alternate method allows Welcome files to be configured on a per portlet basis as a configuration parameter in the portlet deployment descriptor portlet.xml. The default search will look for the initial view file per portlet mode. The other feature in the Struts Portlet Framework is the support for modules. A unique welcome file should be configured for each module by specifying the application prefix. For example, to support the view mode for the markup WML, a welcome file wml/view can be specified. See Example 2 for implementation details.
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>help/index.jsp</welcome-file>
<welcome-file>wml/view/index.jsp</welcome-file>
</welcome-file-list>
<portlet-preferences>
<preference>
<name>viewMode.page</name>
<value>portlet1/welcome.jsp</value>
</preference>
<preference>
<name>editMode.page</name>
<value>html/edit/index.jsp</value>
</preference>
</portlet-preferences>
<config-param>
<param-name>viewMode.page</param-name>
<param-value>portlet1/welcome.jsp</param-value>
</config-param>
<config-param>
<param-name>editMode.page</param-name>
<param-value>portlet1/edit.jsp</param-value>
</config-param>
- A welcome file entry should be configured for each module. The welcome file entry is the initial screen shown when first switching to that module.
- The default Struts configuration, which has a "" prefix, is used any time a module prefix is not found.
Using modes
The Struts Portlet Framework is set up to use the mode and markup to find the Struts configuration. However, if you do not want to use a Struts application in one of the modes, the Struts portlet (Wps)StrutsPortlet should be subclassed. The appropriate service() method should be overridden to implement the wanted behavior. For example, if the developer wants a help mode that does not use a Struts application, then the doHelp() method should be implemented in a subclass.
Portlet modes can be supported with the Struts Portlet framework. The Struts Portlet Framework stores the IViewCommand objects on a per mode basis. That means that an application that supports view and edit mode will have an IViewCommand object for view and edit mode. The welcome file list is typically used for the initial page when entering a mode.
<action path="/nextEditPage2"
type="com.ibm.wps.struts.example.multipleapps.actions.ForwardAction">
<forward className="com.ibm.wps.struts.action.StrutsActionForward"
name="success"
path="/edit3.jsp">
<set-property property="removeOnModeChange"
value="true"/>
</forward>
</action>
<init-param>
<param-name>config/html/help</param-name>
<param-value>/WEB-INF/html/help/struts-config.xml</param-value>
</init-param>
<init-param>
<param-name>ModuleSearchPath</param-name>
<param-value>markupName, porletMode</param-value>
</init-param>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>html/help/index.jsp</welcome-file>
<welcome-file>wml/view/index.jsp</welcome-file>
</welcome-file-list>
Support for devices
The Struts Portlet Framework's support of devices was designed to be flexible. The way the configuration and JSP files are placed in the directory structure should be tolerant of the devices that need to be supported. Some applications may just support HTML browsers and only need a single Struts configuration file. Other applications may support multiple markups and locales but do not need to know specifics about the device itself, while other implementations may need unique implementations for each of the supported devices.
- markupName
- locale
- portletMode
<init-param>
<param-name>ModuleSearchPath</param-name>
<param-value>markupName, portletMode</param-value>
</init-param>
- html/view
- html
- "" ( default configuration )
- wml/view
- wml
- "" ( default configuration )
The search path is checked against all of the prefixes for the ModuleConfig objects for a match. The modules are configured in the web deployment descriptor, web.xml, by specifying a prefix for a Struts configuration.
<init-param>
<param-name>config/wml/view</param-name>
<param-value>/WEB-INF/wml/view/struts-config.xml</param-value>
</init-param>
If the wml/view module is selected, the corresponding JSPs are searched for under the wml/view directory of the Struts application WAR file.
This is a good start for separating the files for different markups and modes, but this granularity is probably not enough to deal with all available devices, or even locales. You can modify this search path to have a finer granularity. For example, you could create a unique module for every phone that they support.
The search path of markupName, portletMode, locale, manufacturer, model, and version could be used. This offers a very fine-grained deployment of the JSPs. The problem with this approach is that the majority of the JSPs would probably be the same for each of the devices. There are probably a few that need to be modified for each device, but this approach does not allow sharing.
This is why two paths are offered, search and include. The search path is used to find the module. This would be for applications that can use a common configuration, share actions and some of the JSPs. The include path can then be used to look for specific implementations of the JSP and if not found, fall back to a common file.
<init-param>
<param-name>IncludesSearchPath</param-name>
<param-value>manufacturer, model, version</param-value>
</init-param>
- wml/view/Acme/T400/index.jsp
- wml/view/Acme/index.jsp
- wml/view/index.jsp
Note that version did not show up in the search. That is because the default client configuration for the T400 did not have one defined. If one was configured at a later time, then it would be used.
Portal aggregation is flexible in how the differences between devices are supported. The common features are supported through the search path; all WML devices in view mode in a locale. The subtitle differences between devices would be supported through the file search of the include path. The common versions of the JSPs would be at a root level, and specific files would be at lower levels.
The Struts example ships with several tags, two of which required a minor change to support modules. The LinkSubscriptionTag and LinkUserTag tags had to be modified so that the current ModuleConfig's prefix had to be added to the computed URL.
Internationalization support
<init-param>
<param-name>IncludesSearchPath</param-name>
<param-value>locale</param-value>
</init-param>
The Struts framework was designed to give the application control over locale by using a locale object that is set in session with a known key. The Struts RequestProcessor sets the locale object for each user during the processLocale() method. The processLocale() method sets the locale object using the key Globals.LOCALE_KEY if the feature is enabled through the Struts configuration file and the attribute has not already been set in session.
A setting on the controller element that is available in the Struts configuration file controls the locale support in Struts. The support can be turned off, which will stop the locale processing in the Request Processor processLocale() method.
WebSphere Portal supports dynamic changes to the locale. Portlets should use the locale object that is obtained through the PortletRequest object for the locale setting. The Struts Portlet Framework sets the locale object in the session using the key Globals.LOCALE_KEY during the actionPerformed() and service() methods. The support is implemented by calling the (Wps)StrutsPortlet processLocale() method, which sets the locale object if one is not found or the locale is different than the one already in session. This assures that a portlet written using the Struts Portlet Framework uses the correct locale.
<init-param>
<param-name>UsePortalsLocale</param-name>
<param-value>false</param-value>
</init-param>
However, in most cases the portlet should use the default implementation.
Using the IBM container
WebSphere Portal also provides an implementation to find globalized JSPs using the include() method on PortletContext. PortletContext inserts the locale into the path to locate the locale-specific JSP. For more information, see Generating markup for multiple devices, markups, and languages.
The Struts Application can be deployed to use the portal server's aggregation method to find globalized JSPs, instead of a resource bundles for each locale. The Struts Portlet Framework uses the PortletContext.include() on the legacy container to include JSP pages, so both methods of globalization are supported.
PortletContext.include() searches for locale-specific files by inserting the markup and locale name in the path. This behavior can be configured through an initialization parameter in the web deployment descriptor. An include search path can be specified that controls how the includes are located. For example, the default implementation would be markup, locale but can be changed to just locale if required. The mode and markup support may have been already configured to include markup, so this configuration allows the markup to not be needed a second time.
WML support
<init-param>
<param-name>config/wml/view</param-name>
<param-value>/WEB-INF/wml/view/struts-config.xml</param-value>
</init-param>
The search path that is set up in the web deployment descriptor, takes markup, mode, and locale into account. When a WAP device connects to a portal server, the markup will be WML, and the mode will be view. This example does not use the locale that is requested.
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>html/help/index.jsp</welcome-file>
<welcome-file>wml/view/index.jsp</welcome-file>
</welcome-file-list>
For more information about WML support in the Struts Portlet Framework, see Changes to Struts JSPs.
Logging
The Struts Portlet Framework uses the Commons-Logging interface for a logging facility. The Struts Portlet Framework has supplied an implementation of the Commons-Logging Log interface that can be used to map the trace messages to the logging facility used by the portal server. This file is normally found in the PortalServer_root/log directory. Setting properties in the wp_profile_root/PortalServer/config/config/log.properties file enables trace logging. The trace string for tracing a Struts portlet application can be configured in log.properties. The trace string can be modified to add or remove classes. The entire trace string must be on one line in log.properties.
The logging in WebSphere Portal typically creates a logging object per class and the trace messages display the log class that the message is from. This is very convenient to determine where a trace message originated from and also allows only enabling the tracing on certain classes.
The typical trace string configured in the log.properties file for tracing a Struts application would be as the following examples (all on one line). This can be modified to add or remove classes.
- Logging conflict between new and old versions of Struts portlets
- The JCL determines the logging implementation by first looking
for the System property org.apache.commons.logging.LogFactory. If
the System property has not been set, it then looks for the org.apache.commons.logging.LogFactory
file in the META-INF/services directory and then
for commons-logging.properties in the classpath.
The value of the System property becomes available to all portlets once it is set, and this would determine the logging implementation class for the portlets on the page. There would be no effect on the logging if the default logging implementation is used by all portlets. However, if the logging implementation class for a portlet is set in a custom common-logging.properties file, it would be ignored. To overcome this, the developer would need to override the method, which sets the System property. See the section Overriding the default logging implementation class for more details.
- Commons Logging jar
- The WebSphere Application Server ships a version of the commons-logging.jar file and specifies the default commons logger to be the com.ibm.ws.commons.logging.TrLogFactory class. If the Struts portlet does not specify a log factory then the default log factory of TrLogFactory is used. However, if the application ships a version of commons-logging, then a ClassCastException will result. This release of the Struts Portlet Framework no longer ships commons-logging.jar, but instead will use the version shipped in the Application Server. Older applications can continue to use the commons-logging.jar file packaged with the Struts Portlet Framework as long as the application specifies a logger, which is the typical case.
Changes to the Struts configuration file
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
In order to have the Struts Portlet Framework operate properly, the RequestProcessor must be configured. The RequestProcessor is responsible for the main functionality of processing a request. The default RequestProcessor can be overridden in the struts-config.xml via the controller element. In the struts-config.xml, the following portal server RequestProcessor must be specified:
- Standard portlet container:
<controller processorClass="com.ibm.portal.struts.portlet.WpRequestProcessor"> </controller>- IBM portlet container:
<controller processorClass="com.ibm.wps.portlets.struts.WpsRequestProcessor"> </controller>
Of course, you may also have had the need to extend the Struts RequestProcessor in order to extend the functionality of Struts. If you simply place the path to your RequestProcessor in the controller element in the struts-config file, your application will not work properly in the portlet environment. Instead, what you should do is have your RequestProcessor class extend the WpsRequestProcessor rather than the normal Struts RequestProcessor.
- processLocale
- processActionPerform()
- processActionForm()
- processActionForward()
- processPath()
- processRoles()
- processMapping()
- processValidate()
- doForward()
- doInclude()
- getMapping()
If you override any of the methods listed previously, you should make sure to invoke the super class version of the method from within your method.
There are existing Struts Extensions which require you to use their RequestProcessor. Clearly, you cannot use their RequestProcessor and the WpsRequestProcessor at the same time. Instead, you would need to get the source to that RequestProcessor and following the approach just described.
Tiles support
Struts integrates the Tiles package for creating views. A Tiles sample is included with the Struts Portlet Framework that demonstrates how to configure Tiles in the Struts Portlet Framework. Tiles requires a specific Request Processor that is configured through a plug-in. The following is from the Struts configuration to show how to configure Tiles for a Struts application that is deployed in WebSphere Portal.
- Standard portlet container:
<!-- add the Tiles plugin. --> <plug-in className="com.ibm.portal.struts.plugins.WpTilesPlugin"> <set-property property="definitions-config" value="/WEB-INF/conf/tiles-def.xml"/> <set-property property="definitions-debug" value="2"/> <set-property property="definitions-parser-details" value="2"/> <set-property property="definitions-parser-validate" value="true"/> </plug-in>The Tiles plug-in requires that compatible request processor is configured in the controller element. The WpTilesPlugin has been written to accept the default Struts RequestProcessor, WpStrutsRequestProcessor, or the WpTilesRequestProcessor.
- IBM portlet container:
<!-- add the Tiles plugin. --> <plug-in className="com.ibm.wps.portlets.struts.plugins.WpsStrutsTilesPlugin"> <set-property property="definitions-config" value="/WEB-INF/conf/tiles-def.xml"/> <set-property property="definitions-parser-details" value="2"/> <set-property property="definitions-parser-validate" value="true"/> </plug-in>The Tiles plug-in requires that compatible request processor is configured in the controller element. The WpsStrutsTilesPlugin has been written to accept the default Struts RequestProcessor, WpsStrutsRequestProcessor, or the WpsStrutsTilesRequestProcessor.