Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Hello World, the simplest portlet for WebSphere Portal V5: Part 2. Rendering with JSP

Ron Lynn (tcat@us.ibm.com), Senior Software Engineer, IBM
Photo: Ron Lynn (a.k.a. tcat)
Ron Lynn (a.k.a. tcat) is a Senior software engineer at IBM's Santa Teresa Lab. Ron has worked on portal projects since before they were called portals. He enjoys learning new technologies and playing with his ever growing family.

Summary:  This article takes the reader through developing and deploying a simple JSP based portlet for IBM WebSphere Portal Version 5.

Date:  31 Mar 2004
Level:  Introductory

Activity:  3333 views
Comments:  

Introduction

In the first article in this Hello World series, you saw how to create a portlet in Java that spits out "hello, world". While this is instructive, it is not a pragmatic approach to developing portlets. So, what is wrong with it? Solving one of the problems is the subject of this second article.

In the simplest "Hello World!" program, the Java code contains both the text "hello, world" and the logic for displaying it. It would be far better if you could separate the logic of the portlet from how it gets rendered, which would let you create portlets that support different meta languages and national languages. Today, you might not have a requirement to create a portlet for Wireless Markup Language (WML) or in the German language. But what about tomorrow?

You could also be working with a graphic designer who frequently changes the look and feel. If rendering is done in Java code, it takes a developer and a recompilation to change it. The solution is to render your portlet with JSP, which lets you create separate JSP files for each supported meta or national language. The designer can have full control over the JSP and change it without ever needing a developer.

In this article, you first see what it takes to build a portlet that calls a JSP for rendering in for IBM® WebSphere® Portal Version 5. Then, you look at the JSP and a few of the tags from the portlet tag library. Finally, you create deployment descriptors, package everything together, and deploy it into the portal.


Creating the directory structure

To start off, you must create a directory structure in which you store your portlet. Here's what you use for this portlet:

  • helloWorld\com\ibm\portlets\sample - where your source will go.
  • helloWorld\WEB-INF - where the deployment descriptor is stored.
  • helloWorld\WEB-INF\lib - where the JAR file will go.
  • helloWorld\jsp - where the JSP files are stored.

Important: All directory and environment references are based on Windows convention. You need to adjust these accordingly for Unix systems.


Creating the Java code

The sample directory is where you put our Java source file. Create a file named HelloWorld.java in the sample directory and open it in your favorite text editor. Here's the class that you need to type (or cut and paste) into the HelloWorld.java file:

package com.ibm.portlets.sample; 
 
//portlet APIs 
import org.apache.jetspeed.portlet.*; 
 
//Java stuff 
import java.io.*; 
 
public class HelloWorld  extends PortletAdapter { 
 
  public void service(PortletRequest request, PortletResponse response) 
    throws PortletException,  IOException { 
 
    // Include the view jsp 
    getPortletConfig().getContext().include( "/jsp/view.jsp",  
          request,  response); 
  } 
}


Compiling the code

After you have created the source file, you are ready to compile the Java code. You can use the script below in a batch file to compile the portlet. Start by defining some environment variables, such as environment variables that define where the Java is installed (JAVA_HOME). It's usually a good idea to compile this using the JDK provided with the WebSphere Application Server, since that is the environment in which you will run the application.

You also need to set the PATH environment variable to include the location where the Java compiler is installed. Set the variable LIBPATH that will point to the directory where the WebSphere JAR files are found.

Next, set a variable called CP for our compilation classpath. The CP variable could be built on a single line, but the listing below breakes it up to show the various JAR files required. You then invoke the Java compiler and compile our code. The code assumes you are in the helloWorld directory. Adjust your directory paths as appropriate for your installation.

set JAVA_HOME=C:\WebSphere\AppServer\java 
set PATH=%JAVA_HOME%\bin 
set LIBPATH=C:\WebSphere\AppServer\lib 
set CP=. 
set CP=%CP%;%LIBPATH%\j2ee.jar 
set CP=%CP%;%LIBPATH%\dynacache.jar 
set CP=%CP%;C:\WebSphere\PortalServer\shared\app\portlet-api.jar 
 
javac -classpath %CP% com\ibm\portlets\sample\HelloWorld.java 

If this doesn't compile, you must fix the errors before moving on. Some common errors are:

  • Typos - mistyped class names, paths, variable names.
  • File name - the file name and the class name must match in our case the file name is HelloWorld.java. and the class name it HelloWorld. If you have changed one, change the other.
  • Editor woes - make sure your editor really saves the file as text. An editor like WordPad does not save as text by default.

Creating the JAR file

After the Java source is compiled, you need to create a JAR file in the WEB-INF\lib directory. Again, the code assumes you are in the helloWorld directory. These statements could be included as part of the batch file you created above. It relies on having the PATH set to get to the jar program.

set JAVA_HOME=C:\WebSphere\AppServer\java 
set PATH=%JAVA_HOME%\bin 
 
jar -cv0f .\WEB-INF\lib\HelloWorldFromJSP.jar com/ibm/portlets/sample/*.class


Creating the JSP file

After the Java source is compiled and the JAR file is created, you can turn your attention to the JSP file. The JSP directory is where you put the JSP source file. Create a file named view.jsp in the JSP directory and open it in your favorite text editor. Here's the JSP code that you need to type (or cut and paste) into the view.jsp file:

Hello world from the JSP!

This is simple enough. Now, you can get this packaged up and running! You cancome back to the JSP afterwards, to see what more you can do to add support for different national and meta languages.


Creating the deployment descriptors

You will need to create two XML files:

  • helloWorld\WEB-INF\web.xml - the web deployment descriptor.
  • helloWorld\WEB-INF\portlet.xml - the portlet deployment descriptor.

web.xml - the web deployment descriptor

The web deployment descriptor is needed for WebSphere Portal. Portlets extend Servlets now, so the web deployment descriptor is needed to declare the Servlet (portlet) class.

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web 
        Application 2.3//EN" 
   "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> 
<web-app id= "HelloWorldFromJSPWebApp"> 
  <display-name>HelloWorldFromJSPPortlet</display-name> 
  <servlet id="Servlet_1"> 
    <servlet-name>HelloWorldFromJSP</servlet-name> 
    <servlet-class>com.ibm.portlets.sample.HelloWorld</servlet-class> 
  </servlet> 
  <servlet-mapping id="ServletMapping_1"> 
    <servlet-name>HelloWorldFromJSP</servlet-name> 
    <url-pattern>/HelloWorldFromJSP/*</url-pattern> 
  </servlet-mapping> 
</web-app>

portlet.xml - the portlet deployment descriptor.

The portlet deployment descriptor defines the portlet to the portal. Each portlet is mapped to a Servlet defined in the web deployment descriptor by way of the href attribute on the portlet element. These references are shown below in bold. A portlet must define a unique id that each concrete portlet can reference. Each concrete portlet references a portlet using the given id in the href attribute of the concrete-portlet element. These references are shown below in blue.

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE portlet-app-def PUBLIC "-//IBM//DTD Portlet Application 
        1.1//EN" "portlet_1.1.dtd"> 
<portlet-app-def> 
  <portlet-app uid="com.ibm.portlets.sample.HelloWorldFromJSP.1" major-version="1"
        minor-version="0"> 
    <portlet-app-name>HelloWorldFromJSP0Portlet</portlet-app-name> 
    <portlet href="WEB-INF/web.xml#Servlet_1" id="Portlet_1" major-version="1"
        minor-version="0"> 
      <portlet-name>HelloWorldFromJSP</portlet-name>
      <cache> 
        <expires>0</expires> 
        <shared>no</shared> 
      </cache> 
      <allows> 
        <maximized/> 
        <minimized/> 
      </allows> 
      <supports> 
        <markup name="html"> 
          <view/> 
        </markup> 
      </supports> 
    </portlet> 
  </portlet-app> 
  <concrete-portlet-app uid="com.ibm.portlets.sample.HelloWorldFromJSP.1.2"> 
    <portlet-app-name>Concrete HelloWorldFromJSP</portlet-app-name> 
    <context-param> 
      <param-name>Author</param-name> 
      <param-value>tcat@us.ibm.com</param-value> 
    </context-param> 
    <concrete-portlet href="#Portlet_1"> 
      <portlet-name>HelloWorldFromJSP</portlet-name> 
      <default-locale>en</default-locale> 
      <language locale="en"> 
        <title>Hello World from JSP</title> 
      </language> 
    </concrete-portlet> 
  </concrete-portlet-app> 
</portlet-app-def>

Many things can go wrong when creating these XML files, and you might not find out until you attempt to deploy the portlet into the portal. Here are some things to double check.

  • Verify that for every XML element you have a closing element.
  • Check for mistyped class names, especially for this example if you named your class something other than HelloWorldFromJSP
  • Make sure your id and href attributes match.
  • Make sure your editor really saves the file as text.

Creating the WAR file

Finally, you are ready to create the WAR file for distribution. You use the standard jar command to build the WAR file. Run this from the helloWorld directory.

set JAVA_HOME=C:\WebSphere\AppServer\java 
set PATH=%JAVA_HOME%\bin 
 
jar -cf HelloWorldFromJSP.war WEB-INF jsp


Deploying the WAR file

  1. Login to the portal as the portal administrator (wpsadmin).
  2. Select the Administration link in the upper right hand corner of the default theme.
    Figure 1. The administration link
    Administration link
  3. Select the Portlets page on the left and the Install portlet.

    Figure 2. Install portlets administration page
    Install Portlets administration page
  4. Click Browse button.
  5. Find the location of WAR file, select it, and click Open button.

    Figure 3. File selection dialog
    File selection dialog
  6. Click Next. This could take some time, so wait for it to finish.
  7. Verify Portlet is HelloWorld. Click Install button. Again, wait for it to complete.

    Figure 4. Portlet install verification screen
    Portlet install verification screen
  8. Finally, you should see this confirmation: Portlet installation successful.

If you get some sort of error during deployment, this usually means that you made a mistake in one of your XML files. Take a look at the error messages you are presented with on the install page. You can usually figure out the problem from there. These messages are also in the latest log file:
%WPS_HOME%/log/wps_YYYY.MM.DD-HH.MM.SS.log

Some common mistakes made with the XML files are listed above. You might also check the following:

  • The XML declaration must be first line in file (no whitespace).
  • The xml files have the correct names, in the correct case.

Adding the portlet to a page

  1. Select Portal User Interface page on the left.
  2. Click the Manage Pages portlet.
    Figure 5. Manage pages portlet
    Mangage pages portlet
  3. Then select the My Portal page.
  4. Click New page.
  5. Enter a title for the new page.
  6. Click OK button.
  7. Click OK button when you see OK success message.
  8. Click the edit page icon, Edit page, next to your new page.
  9. Click Add portlets.
  10. Search for: Hello, click Search.
  11. Select the Hello World portlet and click OK button.

    Figure 6. Search for portlets
    Search for portlets
  12. Click Doneto finish the page layout.
    Figure 7. Edit layout
    Edit layout
  13. Click the My Portal link in the upper right and then select the page that you created.
    Figure 8. Portal displaying our portlet
    Portal displaying our portlet

I18N and multiple meta languages

I18N is the common abbreviation for internationalization, a term which refers to designing an application, (your portlet), in such a way that it can be adapted to different languages and regions without code changes. With your current implementation, you have no way to support multiple national languages or multiple meta languages. Portlets that use JSP for rendering are given two types of support for I18N, one of which also helps with multiple meta languages.

This first support is for multiple JSPs to render your portlet. This support allows a portet to have a different layout, colors, images, text, and other presentation specifics for each supported language, region, and meta language.

The directory structure for your JSP is \jsp\view.jsp. The portal uses this directory as a base to search for a best fit JSP. Here is the order which will be searched by a Web browser set to the US english locale:

\jsp\html\en_US\view.jsp 
\jsp\html\en\view.jsp 
\jsp\html\view.jsp 
\jsp\view.jsp

The first view.jsp found is used for rendering the portlet. This convention allows you to specify different JSPs for different national languages. For example, you could have a view.jsp in the \jsp\html\de\ directory. It would read, "Hallo Welt" (which I hope is "Hello World" in German). The general idea is that each language and region could have its own JSP providing specialized layout and verbage. What about different meta languages? You can see from the search path above that \html\ is specified. You could have JSPs for the portlet in the following paths:

\jsp\html\en_US\view.jsp 
\jsp\html\en\view.jsp 
\jsp\html\de\view.jsp 
\jsp\html\view.jsp 
\jsp\wml\en_US\view.jsp 
\jsp\wml\en\view.jsp 
\jsp\wml\de\view.jsp 
\jsp\wml\view.jsp 
\jsp\view.jsp

Having different JSPs would let your portlet users come in from a WML browser, and the portlet would use the JSPs in the \wml\ directory structure for searching.So, that is the first level of support for I18N.

The second level of help is in the form of Java resource bundles. For the purposes of your portlet, Java resouce bundles give the ability to put strings into properties files that are easily translated, separately from the JSP code. You can have the same layout, but have the text in the correct national language. To do this in WebSphere Portal V5, you need to delve into the world of JSTL, the JSP Standard Tab Library. Previously, you would use the IBM portlet tag library provided with WebSphere Portal to access resource bundles from a JSP. You can still do that in V5, but the text tag is deprecated and the vision for the future is JSTL.


An introduction to JSTL for I18N

JSTL provides JSP tags for a variety of functions. In fact JSTL is actually four different tag libraries.

  1. The core tag library -- which provides an expression language and common control flow tags. Such as and if and looping tags.
  2. The formatting tag library -- which provides I18N features such as message retrieval from resource bundles, date, time, and other formatting tags.
  3. The database access tag library -- allow you to access your database directly from you JSP.
  4. The XML tag library -- various XML tags that allow you to parse and transform XML documents.

I have found that the database and the XML portions of JSTL have a tendency to conflict with other libraries in WebSphere Portal. As an example, when I included the database tag library in a portlet which used a DB2 datasource, I ended up with class conflicts and could no longer access my database. Likewise when I included the XML tag library in a portlet, I found that my JSPs were no longer able to compile.

This little problem only reared its head in WebSphere Portal V5.0.2. I finally figured out it was the JSTL XML tag library that was conflicting. So my suggestion to you is to pare down JSTL to just the formatting and core tag libraries until you feel you have a good handle on which JAR files you actually need.

Speaking of JAR files, you can download the JSTL libraries from Standard tag lib or start at Standard tag lib introduction and find your own mirror site for downloading. This article is illustrating Version 1.0.

When you unzip the downloaded libraries, you find several directories that have been created. The two you are most interested in, to start, are the lib and the tld directories. You need to copy two JAR files from the lib directory to your WEB-INF/lib directory. They are jstl.jar and standard.jar. All the other libraries are not needed for the purpose of this exercies and interfere with the execution of your portlet, as discussed above.

You need to create a WEB-INF/tld directory as well. Copy c.tld, c-rt.tld, fmt.tld, and fmt-rt.tld from the tld directory to your WEB-INF/tld directory. These files define the core (c) tag library and the formatting (fmt) tag libraries. You are probably wondering about now why you need two different tld files. JSTL has a concept of "twin libraries" and it is really beyond the scope of this article. The bottom line is that one allows the use of the JSTL expression language and the other allows one to use JSP expressions.

Yes yes yes, you with the JSTL tattoo and the twisted expression in the back there. Before you whip out your Blackberry and nasty gram me about not doing JSTL justice, I know I am breezing over JSTL, and I encourage you to write an article of you own on JSTL. But you gentle reader, you really should go read about JSTL from a better source than I. Google for it and search in your favorite online bookstore. You'll find plenty of resource, but remember JSTL 1.0!

You got most of the preliminary work done to use JSTL in your portlets to access resource bundles. You must modify the web.xml file to declare the tag libraries you are going to use. Take a look at the taglib tags after the servlet-mapping tags.

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web 
        Application 2.3//EN" 
   "http://java.sun.com/j2ee/dtds/web-app_2_3.dtd"> 
<web-app id= "HelloWorldFromJSPWebApp"> 
  <display-name>HelloWorldFromJSPPortlet</display-name> 
  <servlet id="Servlet_1"> 
    <servlet-name>HelloWorldFromJSP</servlet-name> 
    <servlet-class>com.ibm.portlets.sample.HelloWorld</servlet-class> 
  </servlet> 
  <servlet-mapping id="ServletMapping_1"> 
    <servlet-name>HelloWorldFromJSP</servlet-name> 
    <url-pattern>/HelloWorldFromJSP/*</url-pattern> 
  </servlet-mapping>

  <taglib id="TagLibRev_JSTL_fmt">
    <taglib-uri>http://java.sun.com/jstl/fmt</taglib-uri>
    <taglib-location>/WEB-INF/tld/fmt.tld</taglib-location>
  </taglib>

  <taglib id="TagLibRev_JSTL_fmt_rt">
    <taglib-uri>http://java.sun.com/jstl/fmt_rt</taglib-uri>
    <taglib-location>/WEB-INF/tld/fmt-rt.tld</taglib-location>
  </taglib>

  <taglib id="TagLibRev_JSTL_core">
    <taglib-uri>http://java.sun.com/jstl/core</taglib-uri>
    <taglib-location>/WEB-INF/tld/c.tld</taglib-location>
  </taglib>

  <taglib id="TagLibRev_JSTL_core_rt">
    <taglib-uri>http://java.sun.com/jstl/core_rt</taglib-uri>
    <taglib-location>/WEB-INF/tld/c-rt.tld</taglib-location>
  </taglib>
</web-app>

You have defined all the libraries that you are likely to use. You will not use them all in this article, but I do not think it will do any harm to define them all. Not only that, if I show you here how to define them all, you will not need to guess for your portlets!

Now you get to the actual JSP code. To utilize the JSTL formatting tag library, the following directive is required at the beginning of the JSP to give access to the formatting library:

<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
        

You can use similar directives to utilize the core library. Now you use the formatting library to retrieve a message from a resource bundle.

<fmt:setBundle basename="nls.labels"/>
<fmt:message key="helloWorldLabel"/>
        

This attempts to get the "helloWorldLabel" from the labels properties file. If no suitable properties file is found, then the default is to render what is between the opening and closing text tag, in our case, "Hello world from the JSP!". The properties files are searched in the same fashion as standard ResourceBundles are searched in Java:

<basename>_<lang>_<country>_<variant> 
<basename>_<lang>_<country> 
<basename>_<lang> 
<basename>

For this exercise, you create a couple of properties files:

/WEB-INF/classes/nls/labels_en.properties 
/WEB-INF/classes/nls/labels_de.properties

They will have the following content:

/WEB-INF/classes/nls/labels_en.properties: 
helloWorldLabel=Hello World! 
 
/WEB-INF/classes/nls/labels_de.properties: 
helloWorldLabel=Hallo Welt!

To sum up, the JSP file, /jsp/view.jsp, has the following content:

<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>
<fmt:setBundle basename="nls.labels"/>
<fmt:message key="helloWorldLabel"/>
        

This file, along with the two properties files, produces the following, when the language is set to English in an HTML browser:


Figure 9. Hello World portlet in English
Hello World portlet in English

Then when our language is set to German in our html browser, the portlet will produce:


Figure 10. Hello World portlet in German
Hello World portlet in German

Pretty nifty. Ah, but you ask, how do I update the portlet that you already deployed into the portal? One could just delete the portlet and redeploy. But in a real portal environment, you would lose user data and deployment information. The last section of this article will briefly cover how to update a deployed portlet.


Updating a deployed portlet

  1. Login to the portal as the portal administrator, (wpsadmin.
  2. Select the Administration link in the upper right hand corner of the default theme.
    Figure 1. The administration link
    Administration link
  3. Select the Portlets page on the left and the Install portlet.
  4. Select the Manage Applications portlet
    Figure 11. Manage portlets screen
    Manage applications
  5. In the Web Modules list box, select the HelloWorldFromJSP.war entry.
  6. Click the Update icon button.
  7. Click the Browse icon button.
  8. Find the location of WAR file, select it, and click Open icon.
  9. Click Next icon, this could take some time, so wait for it.
  10. Verify Portlet is HelloWorldFromJSP, click Install icon, again wait for it to complete.
  11. Finally you should see confirmation that says, Successfull update message

Conclusion

There it is. That's how you render your portlet using a JSP. If you worked along with this article, you wrote, compiled, and packaged Java code for a portlet. You created the deployment descriptors and packaged the portlet for distribution and deployment. You then deployed the portlet into your portal. Finally, you rewrote the JSP, internationalized, and updated the deployed portlet. In the course of portlet development you'll do this time and again. Good luck and happy hacking!

Top of page


Resources

About the author

Photo: Ron Lynn (a.k.a. tcat)

Ron Lynn (a.k.a. tcat) is a Senior software engineer at IBM's Santa Teresa Lab. Ron has worked on portal projects since before they were called portals. He enjoys learning new technologies and playing with his ever growing family.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=13470
ArticleTitle=Hello World, the simplest portlet for WebSphere Portal V5: Part 2. Rendering with JSP
publish-date=03312004
author1-email=tcat@us.ibm.com
author1-email-cc=

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers