Introduction to pervasive portals
Portals are very popular today with Internet users and Web content developers. Portals have become the place where both end-users and business-users alike come to use applications and access information. Through customization, portals offer users the flexibility to self-tailor their own views and layouts, and even personalize content to the topics that interest them most, such as stock quotes, weather, or travel.
Businesses especially have taken to the portal craze, since portals offer a manageable, consolidated interface to business-critical information. Internally, companies can dictate the content and applications (called portlets ) that are available to employees and customize this content based on an employee's position. Other users can take advantage of the easy-to-use interface for accessing the often overwhelming amount of information companies make available to them.
Portals are traditionally viewed through a Web browser interface, like Microsoft® Internet Explorer (IE) or Netscape Navigator®, which are rich clients that allow users to simultaneously view multiple applications and allow for client-side processing using Java Applets or rich media, such as Macromedia Flash®. Web developers, therefore, have a vast assortment of tools with which to bring content to users through a portal interface.
Figure 1. IBM WebSphere Portal on a browser
Over time, businesses have steadily pushed to make their workforce more mobile, particularly in professions where employees must travel to customer locations, such as delivery or appliance repair services. Additionally, consumers continue to embrace mobile personal devices. The blend of these two needs has helped drive the demand for mobile Personal Data Assistant (PDA) devices like Palm® handhelds and the PocketPC, as well as other more limited devices, like the SmartPhone. As these devices become more prevalent, and the demand for access to desktop-like applications from these devices continues to rise, portals will become the prominent method used for bringing applications and information to the mobile users who need it.
Figure 2. IBM WebSphere Portal on a SmartPhone
This article introduces the Web developer to portlet programming in a pervasive environment, meaning we will discuss creating portlet applications for devices other than traditional browsers like IE or Netscape®. Devices targeted in this article include Palm handhelds, Pocket PCs, and SmartPhones. This article is intended for developers with at least some level of IBM® WebSphere® Portal portlet development experience, and builds on the fundamental concepts of portlet design to facilitate easy development of applications for pervasive devices.
Let's review the portlet API by taking a quick look at a simple portlet that displays static content (Figure 3). If you are completely unfamiliar with the portlet API, or with portlet deployment within the portal server, refer to the documentation in the WebSphere Portal InfoCenter (see Resources ) for complete descriptions of the APIs, each tag, and related tag values.
Figure 3. Simple Static Weather Portlet code sample
package com.ibm.wps.samples.weather;
import java.io.*; import
org.apache.jetspeed.portlet.*; import
org.apache.jetspeed.portlets.*;
/** * WeatherPortlet.java -- Simple Example
to display weather. */ public class
WeatherPortlet extends AbstractPortlet {
public void init(PortletConfig portletConfig)
throws UnavailableException {
super.init(portletConfig); }
public void service(PortletRequest request,
PortletResponse response) throws
PortletException, IOException {
PrintWriter writer = response.getWriter();
writer.println("<p>The
weather is 78
degress.</p>");
} }
|
This is an extremely basic portlet that simply outputs the static message, "The weather is 78 degrees". It shows the basic class interface, AbstractPortlet, that needs to be extended in order to create a new portlet application. Like servlets, a portlet has a service method that must be overridden in order to return the content for the portlet window. This example shows how to get PrintWriter from the PortletResponse object to write the HTML content to the output stream.
Figure 4. Simple Static Weather Portlet Output
Our next example is more advanced. In Figure 5, the portlet dynamically retrieves the weather from a weather service for a specified zip code. Additionally, the message is no longer hard coded, but instead is deferred to a JSP for rendering.
Figure 5. Enhanced Weather Portlet code sample
package com.ibm.wps.samples.weather;
import java.io.*; import
vendor.service.weather.*; import
org.apache.jetspeed.portlet.*; import
org.apache.jetspeed.portlets.*; import
org.apache.jetspeed.portlet.service.*;
/** * WeatherPortlet.java -- A more
extensive example to display weather. */ public
class WeatherPortlet extends PortletAdapter {
protected static final String jsp =
"/WEB-INF/weather/html/DisplayWeather.jsp"
public void init(PortletConfig portletConfig)
throws UnavailableException {
super.init(portletConfig); }
public void doView(PortletRequest request,
PortletResponse response) throws
PortletException, IOException {
// Create a Weather Bean. WeatherBean
weatherBean = new WeatherBean();
// Get the portlet session. PortletSession
session = request.getPortletSession();
// Get the portlet configuration. PortletConfig
config = getPortletConfig();
// Get the portlet context. PortletContext
context = config.getContext();
// Get portal user object. User user =
session.getUser();
// Get the user's full name or null if not
available.
weatherBean.setFullName(user.getFullName());
// Get the weather service for determining the
temperature. WeatherService weatherService =
(WeatherService)context.getService(WeatherService.class);
// Get the current temperature for the
specified zip code. weatherBean.setTemperature(
weatherService.getTemperature(
Integer.parseInt(config.getInitParameter("ZipCode"))));
// Put the bean in the request.
request.setAttribute("weatherBean",
weatherBean);
// Invoke the JSP to do the actual rendering
for the portlet view. context.include(jsp,
request, response); } }
|
Let's dissect this example to examine the important components. The first thing to notice is that the WeatherPortlet class no longer extends the AbstractPortlet class, but instead extends the PortletAdapter class. The PortletAdapter class is an implementation of the central portlet abstraction, the portlet interface. It provides default empty implementations for the following portlet methods: init, login, service, logout and destroy.
Next, notice that the class no longer directly overrides the service method. Instead, it overrides a method associated with a particular portlet mode. Portlets have four modes of operation:
- Portlet.Mode.VIEW
- Portlet.Mode.EDIT
- Portlet.Mode.HELP
- Portlet.Mode.CONFIGURE
The operation of these modes is indicated by their names. For each mode, the PortletAdapter class provides a default empty implementation method. In Figure 5, the portlet only supports the VIEW mode, so only the one corresponding doView method has been overridden. It is the default implementation of the service method that determines the portlet mode and calls the appropriate mode method, as indicated by the code fragment in Figure 6, below:
Figure 6. Determining portlet mode
public void service(PortletRequest request,
PortletResponse response) throws
PortletException, IOException {
// Get the mode of the portlet. Portlet.Mode
mode = request.getMode();
if (mode == Portlet.Mode.VIEW) doView(request,
response); else if (mode == Portlet.Mode.EDIT)
doEdit(request, response); else if (mode ==
Portlet.Mode.HELP) doHelp(request, response);
else if (mode == Portlet.Mode.CONFIGURE)
doConfigure(request, response); }
|
Let's examine what occurs when the portlet is called to render its VIEW mode.
The first thing that happens is the creation of an instance of a WeatherBean (Figure 7) that will contain all relevant data necessary to render the display, which in this case is the user name and the weather for the preconfigured zip code. The user name is retrieved from the user object as shown. In order to determine the temperature, the zip code is first retrieved from the PortletConfig object (our simplifying assumption here is that the portlet is configured by an administrator for a certain zip code for all users). Second, a reference to a PortletService is obtained (in particular, this example references a WeatherService object). To limit the complexity of this example, we will assume a weather service has been registered with the portal server and portlets can obtain the current weather for a certain zip code utilizing this service. Once these two pieces of information are obtained, they are stored in the WeatherBean.
Figure 7. WeatherBean code sample
package com.ibm.wps.samples.weather;
/** * WeatherBean.java -- A bean used to
pass data to the JSP display. */ public class
WeatherBean {
/** The user's full name. */ private String
fullName = "";
/** The current temperature. */ private int
degrees = 0;
public void setFullName(String name) { fullName
= name; }
public String getFullName() { return fullName;
}
public void setTemperature(int degrees) {
this.degrees = degrees; }
public int getTemperature() { return degrees; }
}
|
The bean is passed from the PortletAdapter class to the JSP that will ultimately render the display. This is done through the setAttribute method on the PortletRequest object. The JSP then establishes a reference to the bean using the useBean tag and embeds the value of the user's full name and the current temperature in the HTML output markup.
Figure 8. DisplayWeather code sample
<!-----------------------------------------------------------------------------> <!-- --> <!--> DisplayWeather.jsp - A JSP used to render the data for the weather --> <!-- portlet. --> <!-- --> <!-----------------------------------------------------------------------------> <%@ page contentType="text/html" errorPage="" %> <jsp:useBean id="weatherBean" class="com.ibm.wps.samples.weather.WeatherBean" scope="request"/> <p> Hi <%= weatherBean.getFullName() == null ? "" : weatherBean.getFullName() %>! <br> The current temperature in your area is <%= weatherBean.getTemperature() %>. |
The output for this portlet (Figure 9) looks similar to our previous example.
Figure 9. Enhanced Weather Portlet
So far, we've only examined a portlet that renders its display strictly for browsers like IE and Netscape, which implement the full HTML specification. But what if you want to extend the portlets beyond these rich clients and make the content available to constrained devices such as a PocketPC, a Palm handheld or a SmartPhone? In the sections that follow, we will investigate the additional APIs provided by IBM WebSphere Portal that help with development for these devices. We will also examine more advanced topics that are not currently addressed in these APIs, and even demonstrate ways to augment the published methods.
For details on some of the more advanced portlet API topics not covered in this example, such as windowing states, event handling, instance data, etc., consult the WebSphere Portal InfoCenter (see Resources ).
Introduction to pervasive programming
One of the design patterns of object-oriented design is Model-View-Controller, or MVC. MVC is a surprisingly simple, yet incredibly useful pattern that forces the developer to envision an application in terms of three fundamental components:
- The model is the main component that maintains the state and data model that the application represents.
- The controller is a bridge between the model and its views. It is the component that a user can manipulate to change the underlying data model.
- The view is a graphical representation of the data model to the user.
The power in this design is that it provides for:
- Clarity -- the logical components of a design are distinctly separated.
- Modularity -- the various components of the application can be swapped in and out as desired, making debugging much easier.
- Multiple views -- views are scalable in that multiple implementations can be made to represent the same data model.
- Scalable design -- as the application grows, so too can the various components without affecting the underlying application logic.
Figure 10. Model-View-Controller (MVC) Design Pattern
Pervasive portlet programming techniques
Now that we have a background for a modular approach to application development, let's apply it to pervasive programming. We can break down the components in our weather example as follows:
| model: | The core weather application, such as accessing to the user's full name or the weather service to retrieve the current temperature. |
| controller: | The provisioning of the bean that bridges data between the portlet code and the JSP. |
| view: | The DisplayWeather JSP that renders the graphical display for the portlet content. |
It is now easy to see how the model remains the same regardless of the actual display that is rendered. The controller will essentially remain the same between views, but may need to perform some special customization of data based on the intended view. The view component has the flexibility to render the data for a best fit on the destination display. For example, SmartPhones display content in WML (Wireless Markup Language). For our Weather example, then, we can define a separate view JSP for each intended device: an HTML JSP for browsers, and a WML JSP for SmartPhones. Look at the sample portlet in Figure 11, which uses this design scheme and the WebSphere Portal pervasive APIs.
Figure 11. Defining separate views for each device
package com.ibm.wps.samples.weather;
import java.io.*; import
com.ibm.wps.portlets.*; import
vendor.service.weather.*; import
org.apache.jetspeed.portlet.*; import
org.apache.jetspeed.portlets.*; import
org.apache.jetspeed.portlet.service.*;
/** * WeatherBaseController.java * Base
controller class containing common controller
functionality. */ public class
WeatherBaseController extends
AbstractPortletController {
/** The View for HTML devices (e.g. Internet
Explorer, Netscape). */ protected String
jspHTML =
"/WEB-INF/weather/html/";
/** The View for WML devices (e.g.
SmartPhones). */ protected String jspWML =
"/WEB-INF/weather/wml/";
public void init(PortletConfig config) throw
UnavailableException {
super.init(config);
// Load the HTML View from the configuration
jspHTML +=
config.getInitParameter("view.HTML");
// Load the WML View from the configuration.
jspWML +=
config.getInitParameter("view.WML");
}
protected void createBean(PortletRequest
request, PortletResponse response) {
// Get the portlet configuration object.
PortletConfig config = getPortletConfig();
// Create a Weather Bean. WeatherBean
weatherBean = new WeatherBean();
// Set the user's full name or null if not
available. weatherBean.setFullName(
request.getPortletSession().getUser().getFullName());
// Get the weather service for determining the
temperature. WeatherService weatherService =
(WeatherService)config.getContext().getService(WeatherService.class);
// Get the current temperature for the
specified zip code. weatherBean.setTemperature(
weatherService.getTemperature(
integer.parseInt(config.getInitParameter("ZipCode"))));
// Insert bean into the request for the JSP to
use.
request.setAttribute("weatherBean",
weatherBean); } }
|
package com.ibm.wps.samples.weather;
import java.io.*; import
com.ibm.wps.portlets.*; import
org.apache.jetspeed.portlet.*;
/** * WeatherHTMLController.java * Controller
for calling the HTML View. */ public class
WeatherHTMLController extends
WeatherBaseController {
public void doView(PortletRequest request,
PortletResponse response) throws
PortletException, IOException {
createBean(request, response);
getPortletConfig().getContext().include(jspHTML,
request, response); }
|
package com.ibm.wps.samples.weather;
import java.io.*; import
com.ibm.wps.portlets.*; import
org.apache.jetspeed.portlet.*;
/** * WeatherWMLController.java * Controller
for calling the WML View. */ public class
WeatherWMLController extends
WeatherBaseController {
public void doView(PortletRequest request,
PortletResponse response) throws
PortletException, IOException {
createBean(request, response);
getPortletConfig().getContext().include(jspWML,
request, response); } }
|
This example shows a base controller that contains common function for both the HTML and WML views. First, in the init method, the name of the HTML and WML view JSPs from the portlet configuration are loaded. Second, a method called createBean is provided that creates an instance of the WeatherBean and populates it with the model data. Last, the createBean method inserts the bean into the request, making it available to a view JSP.
The next two classes (Figure 12) represent controllers for each of the view types. The first is the HTML controller and the second is the WML controller. Both controller classes extend the base controller class to inherit the common functionality it provides. For simplicity, there is not much difference between the two controllers except for what view they call. However, you can imagine providing special functions tailored to each device type depending on the actions taken by the user. For example, a rich client controller may provide drag and drop controls for icons, whereas a thin client controller would not.
In order for these controllers to work, you need to register them with the portlet
web.xml
file by adding the following configuration markup. (Details of the
web.xml
and
portlet.xml
files have been left out of this example. For more information, consult the
Resources
section for WebSphere Portal InfoCenter documentation.)
Figure 12. HTML & WML controllers
<servlet-name>WeatherPortlet</servlet-name> <servlet-class>com.ibm.wps.portlets.MVCPortlet</servlet-class> <init-param> <param-name>controller.html</param-name> <param-value>com.ibm.wps.samples.weather.WeatherHTMLController</param-value> </init-param> <init-param> <param-name>controller.wml</param-name> <param-value>com.ibm.wps.samples.weather.WeatherWMLController</param-value> </init-param> <init-param> <param-name>view.HTML</param-name> <param-value>DisplayWeatherHTML.jsp</param-value> </init-param> <init-param> <param-name>view.WML</param-name> <param-value>DisplayWeatherWML.jsp</param-value> </init-param> <init-param> <param-name>ZipCode</param-name> <param-value>27709</param-value> </init-param> |
Now we need to supply the two view JSPs, one for HTML, the other for WML (Figure 13). Since the HTML view is intended for a rich client, we will show the user name, but omit it from the WML view since this is a more constrained client.
Figure 13. HTML and WML JSPs
<!-----------------------------------------------------------------------------> <!-- DisplayWeatherHTML.jsp - A JSP view for rendering HTML. --> <!-----------------------------------------------------------------------------> <%@ page contentType="text/html" errorPage="" %> <jsp:useBean id="weatherBean" class=";com.ibm.wps.samples.weather.WeatherBean" scope="request"/> <p> Hi <%= weatherBean.getFullName() == null ? "" : weatherBean.getFullName() %>! <br> The current temperature in your area is <%= weatherBean.getTemperature() %>. |
<!-----------------------------------------------------------------------------> <!-- DisplayWeatherWML.jsp - A JSP view for rendering WML. --> <!-----------------------------------------------------------------------------> <%@ page contentType="text/wml" errorPage="" %> <jsp:useBean id="weatherBean" class="com.ibm.wps.samples.weather.WeatherBean" scope="request"/> <p align="left"> Current temperature is <%= weatherBean.getTemperature() %>. </p> |
Figures 14 and 15 show how these portlets are rendered on a browser and a SmartPhone, respectively:
Figure 14. Weather Portlet using HTML JSP
Figure 15. Weather Portlet using WML JSP
So far, this article has only described how to provide views for a large categorization of devices. Assuming that a broad range of devices will possess the same capabilities, however, is not usually appropriate, particularly when referring to mobile devices. For example, some SmartPhones support WML version 1.1, others support a subset of WML 1.2 (e.g. no tables), and still others support the whole WML 1.2 specification. How, then, do you provide a view that is intelligent enough to take into account all these device variations without resorting to one that supports only the least common denominator of capabilities?
The IBM WebSphere Portal API provides a mechanism for a portlet to query the capabilities of the device for which the portlet view is intended. Instead of requiring every portlet to understand the capabilities of all User-Agent types, the portal provides an abstraction between the User-Agent and device capabilities. How does the portal determine device capabilities? When an HTTP request is made to the portal, the requesting device sends an HTTP field, User-Agent, that contains tokens of information about the requesting device. For example, a Nokia Communicator 9110 sends the following User-Agent field:
Figure 16. User-Agent field sample
| Nokia-Communicator-WWW-browser/3.0 (Geos 3.0 Nokia-9110) |
The portal internally maintains mapping from the User-Agent field to the expected capabilities of the device (see the WebSphere Portal InfoCenter in the Resources section). Thus, the portal can infer the capabilities of a device and provide that information to a portlet. This allows for a scalable design in that new User-Agent mappings can be added to the portal as new devices become available, but portlets need not change their behavior. Rather, they use the same device capabilities abstraction to infer how a particular view should be rendered.
This capabilities abstraction class, appropriately called Capability, is a part of the
org.apache.jetspeed.portlet
package. It provides generic capability attributes, such as what level of markup is supported (e.g. WML 1.1 vs. WML 1.2), as well as more specific capabilities, like what specific type of function is supported (e.g. JavaScript vs. no JavaScript). In our weather example, we can modify the WML JSP to take into account the capabilities of the WML client. If the client does not support WML tables, then we will output straight text. Otherwise, a table that lists the user name as well as the current temperature in separate rows will be output, as in Figure 17.
Figure 17. WML JSP using device capabilities
<!----------------------------------------------------------------------------->
<!-- DisplayWeatherWML.jsp - A JSP
view for rendering WML using the -->
<!-- capabilities of the device.
-->
<!----------------------------------------------------------------------------->
<%@ page
contentType="text/wml"
errorPage=""
%> <%@ page
import="org.apache.jetspeed.portlet.*"
%>
<jsp:useBean
id="weatherBean"
class="com.ibm.wps.samples.weather.WeatherBean"
scope="request"/>
<!-- Add statements so that we can
access the portlet request/response.
--> <%@ taglib
uri="/WEB-INF/tld/portlet.tld"
prefix="portletAPI"
%> <portletAPI:init
/>
<p
align="left">
<% if
(portletRequest.getClient().isCapableOf(Capability.WML_TABLE))
{ %>
<table
columns="1">
<tr><td>
Hi <%= weatherBean.getFullName() ==
null ? "" :
weatherBean.getFullName() %>!
</td></tr>
<tr><td>
Current temperature is <%=
weatherBean.getTemperature() %>.
</td></tr>
</table>
<% } else { %>
Current temperature is <%=
weatherBean.getTemperature() %>.
<% } %>
</p>
|
For a client phone that does not support WML tables, the output will be the same as our previous JSP example. For phones that do support WML tables, the output will now look similar to Figure 18.
Figure 18. Weather Portlet using WML JSP with tables
The final topic of this article focuses on a solution for more advanced capability attributes. The example we will use has to do with whether or not a client device supports Cascading Style Sheets (CSS). This attribute is important because the portal uses CSS for applying the theme and skin for the overall portal look-and-feel. It is recommended that portlet developers adhere to the published portlet style guidelines (see Resources ) by placing CSS class identifiers in their HTML so that, for example, when a font color is changed, the portlet will pick up that change in color. The HTML content fragment in Figure 19 demonstrates using the style guidelines for the font style of portlet text:
Figure 19. Using style guidelines
<font class="wpsPortletText"> Current temperature is <%= weatherBean.getTemperature() %>. </font> |
Using the CSS class identifier wpsPortletText, the portlet will inheret the style of the CSS when the client device applies it.
The problem with many new medium-rich clients is that they currently support only a limited subset of HTML that does not include support for CSS, making it not possible to apply a style sheet at the client. Thus, portlets written using this guideline will not display correctly.
One possible solution is to provide another level of abstraction for the view. This abstraction can take the form of a style bean that a view can use to appropriately format the content based on the client capabilities. In our example device, which does not support CSS, what needs to be done is that the values of the style need to be directly inserted into the JSP. However, when the device does support CSS, the view should add the recommended style guideline class identifier, as in Figure 20.
Figure 20. Style bean based on client capabilities
<!-- For a device that supports CSS. --> <font class="wpsPortletText"> Current temperature is <%= weatherBean.getTemperature() %>. </font> |
<!-- For a device that does NOT support CSS. --> <font size="1" face="sans-serif"> Current temperature is <%= weatherBean.getTemperature() %>. </font> |
To create this level of abstraction, the bean API in Figure 21 is defined for use by a portlet view JSP to determine what font style should be used for content.
Figure 21. Sample API for portlet view JSP
/** * StyleBean.java * An abstraction layer
for creating a views based on the capabilities
of a * client. For example, CSS support vs. no
CSS support. */ public abstract class StyleBean
{
/** * Initialize the bean. * @param request The
portlet request object. */ public abstract void
init(PortletRequest request);
/** * Method to call to insert the font style
guideline content. * @param styleClass The name
of the style class. * @return The markup to
insert into the JSP for starting a font. */
public abstract String startFont(String
styleClass);
/** * Method to call to insert the font style
guideline content. * @param styleClass The name
of the style class. * @return The markup to
insert into the JSP for ending a font. */
public abstract String endFont(String
styleClass); }
|
Now, an HTML view can simply use this bean to render the necessary content, as shown in Figure 22.
Figure 22. DisplayWeather code sample
<!----------------------------------------------------------------------------->
<!-- DisplayWeatherHTML.jsp - A JSP
view for rendering HTML for both -->
<!-- browsers and Pocket PC devices.
-->
<!----------------------------------------------------------------------------->
<%@ page
contentType="text/html"
errorPage=""
%>
<%@ page
import="org.apache.jetspeed.portlet.*"
%> <%@ page
import="com.ibm.wps.style.*"
%>
<jsp:useBean
id="weatherBean"
class="com.ibm.wps.samples.weather.WeatherBean"
scope="request"/>
<jsp:useBean
id="styleBean"
class="com.ibm.wps.style.StyleBean"
scope="request"/>
<!-- Add statements so that we can
access the portlet request/response.
--> <%@ taglib
uri="/WEB-INF/tld/portlet.tld"
prefix="portletAPI"
%> <portletAPI:init
/>
<!-- Initialize the style bean.
--> <%
styleBean.init(portletRequest); %>
<!----------------------------------------------------------------------------->
<p> <%=
styleBean.startFont("wpsPortletText")
%> The current temperature in your
area is <%=
weatherBean.getTemperature() %>.
<%=
styleBean.endFont("wpsPortletText")
%> </p>
|
The bean itself will take care of deciding which content to render, based on whether the client supports CSS or not. This is only one example of what the bean can be used for. The bean API can be extended to support more markup tags, like table headers, background colors, etc. The code in Figure 23 shows how to implement the StyleBean using the portal APIs.
Figure 23. Implementing the StyleBean using the portal APIs
package com.ibm.wps.style;
import java.io.*; import java.util.*; import
org.apache.jetspeed.portlet.*;
public class StyleBean {
/** The resource that defines the style values.
*/ private ResourceBundle resource = null;
public void init(PortletRequest request) {
// Determine whether the client device supports
CSS and if not, // then load the resource style
values. if
(!request.getClient().isCapableOf(Capability.HTML_CSS))
{
try {
// Retrieve the resource bundle from the
classpath. resource =
ResourceBundle.getBundle("com.ibm.wps.style.NoCSS");
} catch (Exception e) {
// Resource bundle not available. resource =
null; }} }
public String startFont(String styleClass) {
// If the client supports CSS, use class
identifier. if (resource == null) { return
"<font
class=\"" +
styleClass +
"\">";
}
// If the client does not support CSS, use the
style values. String markup =
"<font
size=\"" +
resource.getString(styleClass +
".font.size") +
"\"
face=\"" +
resource.getString(styleClass +
".font.face") +
"\">";
return markup; }
public String endFont(String styleClass) {
return
"</font>";
} }
|
StyleBean makes use of a properties file loaded as a Java resource bundle in order to determine the values for the style attributes. This means that the resource bundle must be packaged with StyleBean or at least in the same classpath. The following is the
NoCSS.properties
file contents:
Figure 24. NoCSS properties file
| wpsPortletText.font.size = 1 wpsPortletText.font.face = sans-serif |
The
NoCSS.properties
file can be modified without code changes to make style modifications for a device that does not support CSS. The bean only currently provides an abstraction for font styles, but it would be easy to extend the interface for other style types. Although not shown in this example, it is also possible to modify the StyleBean class so that the init method could open the appropriate CSS, instead of referencing the properties resource bundle. It would then parse out the wpsPortletText style attributes directly and use those instead, ensuring that the styles being used in the portlets are always consistent with the other HTML devices that also support CSS.
This article just touches on the vast potential of pervasive portlet programming. Between getting started with portlet development, using the Model-View-Controller paradigm and the pervasive MVC API, and discussing how to deal with fine-grained device capabilities and a possible solution for the problem associated with the lack of support for Cascading Style Sheets, the concepts in this article were designed to give you a feel for the basic structure of pervasive portlet programming. I wish you luck in extending these ideas into your own development projects.
IBM, DB2, and WebSphere are trademarks or registered trademarks of IBM Corporation in the United States, other countries, or both.
Windows and Windows NT are registered trademarks of Microsoft Corporation in the United States, other countries, or both.
Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States, other countries, or both.
Other company, product, and service names may be trademarks or service marks of others.
IBM copyright and trademark information
-
Visit the
WebSphere Portal product site
for a variety of resources such as product information, demos, toolkits, and more.
-
The
WebSphere Portal InfoCenter
provides fast, centralized access to information to help you work with WebSphere Portal.
-
Download portlets from the
IBM Portlet Catalog
.
Michael Wanderski is a developer and architect for WebSphere Portal and related products. You can contact Michael at mwanders@us.ibm.com.




