Sun Java System Portal Server 7 Developer's Guide

Developing the Provider Class File

This section includes information on the requirements for developing a provider’s class file. It contains:

Provider Class File Location

The provider classes must be deployed in the provider class base directory specified in the file PortalServer-DataDir/portals/portal-ID/config/desktopconfig.properties. By default, the provider class base directory is PortalServer-DataDir/portals/portal-ID/desktop/classes.

For hot deployment, the JAR file has to be dropped in the directory mentioned in providerClassBaseDir variable in the desktopconfig.properties file.

Provider Class File

The custom provider classes and all other custom classes that the provider classes reference can be bundled into a JAR file and placed in the provider class base directory. They can also exist as .class files in the provider class base directory.

If a class exists in a file and is also present in a JAR file under the provider class base directory, the class existing as a file under the provider class base directory is given the first preference. Once the class is found as a file, no attempt is made to check for its existence in a JAR file.

If a class file exists in two JAR files under the provider class base directory, the class is picked up from one of them at runtime. Do not duplicate classes in multiple JAR files.

When compiling the class file, the Servlet 2.2 API (servlet.jar) and PAPI (PortalServer-base/sdk/desktop/desktopsdk.jar) are required in the CLASSPATH. That is, when compiling a *Provider.java file, you must type:

javac -d PortalServer-DataDir/portals/portal-ID/desktop/classes -classpath PortalServer-base/sdk/desktop/desktopsdk.jar:AccessManager-base/lib/servlet.jar *Provider.java

Provider Class Loader

To support hot deployment of Provider classes the Portal Server has a Provider classloader implementation that can pickup changes to custom classes in the Provider Classloader directory. The provider class loader in the Portal Server software is used to load the classes.

A Provider Classloader instance loads all custom provider classes and resource bundles. When a class in the Provider Classloader directory changes, the Provider classloader and all the classes it loaded are discarded; a new Provider Classloader object is created and this one reloads all the custom classes.

In order to upload a new version of a custom provider class without restarting the server, if the original class existed in a JAR file, rebuild the JAR with the new version of the class file and copy the JAR into the provider class base directory. Or, Just copy the new version of the class as a file into the provider class base directory.

In order to reload a property file, that is being used by a custom provider, with a modified property inside a resource bundle in the provider class base directory without restarting the server, change the last modified time on the custom provider class. If the custom provider class exists:

The presence of the provider class loader has an impact on the design of a multi-channel application in the Desktop. When an object reference is cast from one type to another, not only does the class of the variable need to match the class of the object, the two associated class loaders have to be the same too. This constraint can show up when objects are being passed between different channels in the Desktop.

For example, consider a portal application that uses two providers, one for a container and the other for several leaf channels. Call these providers HeadlineContainerProvider and HeadlineProvider. The container provider performs some common processing for the leaf channels, and then the leaf channels access the container object to get the results of that processing. One way to implement this would be to have the HeadlineContainerProvider put a reference to itself into the request object. For example, in the HeadlineContainerProvider.getContent(), do:

request.setAttribute("HeadlineContainer", this);

Then, in the HeadlineProvider.getContent() method, do:

HeadlineContainerProvider hcp = (HeadlineContainerProvider)request.getAttribute("HeadlineContainer");

This example will compile, but when the desktop loads and runs this code, the HeadlineProvider will cause a ClassCastException on this second statement. The reason is that the HeadlinerContainerProvider object is loaded by one provider class loader object and the HeadlineProvider object is loaded by a different class loader object. The class loader for HeadlineProvider also loads HeadlineContainerProvider because HeadlineProvider references HeadlineContainerProvider. So we have:

The HeadlineContainerProvider class is also loaded by loader2 because of the reference to it in the HeadlineProvider code. The cast is from the object container1 (loaded by loader1) to the variable hcp (of type HeadlineContainerProvider loaded by loader2). Thus the cast fails because the class loaders are not the same.

To understand a case where the classes could actually be different, consider the case where container1 is loaded at time 0, and channel1 is loaded at time 10, but the HeadlineContainerProvider class files was updated on disk at time 5. This means that channel1 will be running with a different version of the HeadlineContainerProvider class than that being used for container1. The case must fail because the class versions are different.

To implement this type of application, an alternate solution is to pass an object as a request or session property that has a class that is not in the PortalServer-DataDir/portals/portal-ID/desktop/classes directory, such as String, Set, or Hashmap. These classes are never reloaded except when the server restarts. The data that you store in that object becomes a contract between different versions of the classes that use that object.