JBoss.orgCommunity Documentation

Chapter 10. Content Integration

10.1. Window content
10.2. Content customization
10.3. Content Driven Portlet
10.3.1. Displaying content
10.3.2. Configuring content
10.3.3. Step by step example of a content driven portlet
10.4. Configuring window content in deployment descriptor

Since JBoss Portal 2.6 it is possible to provide an easy integration of content within the portal. Up to the 2.4 version content integration had to be done by configuring a portlet to show some content from an URI and then place that portlet on a page. The new content integration capabilities allows to directly configure a page window with the content URI by removing the need to configure a portlet for that purpose.

Note

We do not advocate to avoid the usage portlet preferences, we rather advocate that content configuration managed at the portal level simplifies the configuration: it helps to make content a first class citizen of the portal instead of having an intermediary portlet that holds the content for the portal. The portlet preferences can still be used to configure how content is displayed to the user.

The portal uses portlets to configure content

The portal references directly the content and use portlet to interact with content

The content of a window is defined by

At runtime when the portal needs to render a window it delegates the production of markup to a content provider. The portal comes with a preconfigured set of providers which handles the portlet and the cms content types. The most natural way to plug a content provider in the portal is to use a JSR 286 Portlet. Based on a few carefully chosen conventions it is possible to provide an efficient content integration with the benefit of using standards and without requiring the usage of a proprietary API.

Content providers must be able to allow the user or administrator to chose content from the external resource it integrates in the portal in order to properly configure a portal window. A few interactions between the portal, the content provider and the portal user are necessary to achieve that goal. Here again it is possible to provide content customization using a JSR 286 Portlet. For that purpose two special portlet modes called edit_content and select_content has been introduced. It signals to the portlet that it is selecting or editing the content portion of the state of a portlet. select_content is used to select a new content to put in a window while edit_content is used to modify the previously defined content, often the two modes will display the same thing. The traditional edit mode is not used because the edit mode is more targeted to configure how the portlet shows content to the end user rather than what content it shows.

Example of content customization - CMS Portlet

Portlet components are used to integrate content into the portal. It relies on a few conventions which allow the portal and the portlet to communicate.

The editor is probably the longest part of the portlet. It tries to stay simple though and goes directly to the point.

Content editor of FSContentDrivenPortlet in action
protected void doEditContent(RenderRequest req, RenderResponse resp)
                  throws PortletException, PortletSecurityException, IOException
{
   String uri = req.getParameter("current_uri");
   if (uri == null)
   {
     // Get the uri value optionally provided by the portal
     uri = req.getParameter("uri");
   }

   // Get the working directory directory
   File workingDir = null;
   String currentFileName = null;
   if (uri != null)
   {
      workingDir = getFile(uri).getParentFile();
      currentFileName = getFile(uri).getName();
   }
   else
   {
      // Otherwise try to get the current directory we are browsing,
      // if no current dir exist we use the root
      String currentDir = req.getParameter("current_dir");
      if (currentDir == null)
      {
         currentDir = "/";
      }
      workingDir = getFile(currentDir);
   }

   // Get the parent path
   String parentPath = getContentURI(workingDir.getParentFile());

   // Get the children of the selected file, we use a filter
   // to retain only text files and avoid WEB-INF dir
   File[] children = workingDir.listFiles(filter);

   // Configure the response
   resp.setContentType("text/html");
   PrintWriter writer = resp.getWriter();

   //
   writer.print("Directories:<br/>");
   writer.print("<ul>");
   PortletURL choseDirURL = resp.createRenderURL();
   if (parentPath != null)
   {
      choseDirURL.setParameter("current_dir", parentPath);
      writer.print("<li><a href=\"" + choseDirURL + "\">..</a></li>");
   }
   for (int i = 0;i < children.length;i++)
   {
      File child = children[i];
      if (child.isDirectory())
      {
         choseDirURL.setParameter("current_dir", getContentURI(child));
         writer.print("<li><a href=\"" + choseDirURL + "\">" + child.getName() +
                      "</a></li>");
      }
   }
   writer.print("</ul><br/>");

   //
   writer.print("Files:<br/>");
   writer.print("<ul>");
   PortletURL selectFileURL = resp.createActionURL();
   selectFileURL.setParameter("content.action.select", "select");
   for (int i = 0;i < children.length;i++)
   {
      File child = children[i];
      if (child.isFile())
      {
         selectFileURL.setParameter("current_uri", getContentURI(child));
         if (child.getName().equals(currentFileName))
         {
            writer.print("<li><b>" + child.getName() + "</b></li>");
         }
         else
         {
            writer.print("<li><a href=\"" + selectFileURL + "\">" + child.getName() + "</a></li>");
         }
      }
   }
   writer.print("</ul><br/>");

   //
   writer.close();
}
Management portlet with filesystem content type enabled

Finally we need to make the portal aware of the fact that the portlet can edit and interpret content. For that we need a few descriptors. The portlet.xml descriptor will define our portlet, the portlet-instances.xml will create a single instance of our portlet. The web.xml descriptor will contain a servlet context listener that will hook the content type in the portal content type registry.

First, we need to define the portlet's particular event and render parameters:

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
             version="2.0">
             
   <portlet>
      <description>File System Content Driven Portlet</description>
      <portlet-name>FSContentDrivenPortlet</portlet-name>
      <display-name>File System Content Driven Portlet</display-name>
      <portlet-class>org.jboss.portal.core.samples.basic.FSContentDrivenPortlet</portlet-class>
      <supports>
         <mime-type>text/html</mime-type>
         <portlet-mode>VIEW</portlet-mode>
         <portlet-mode>EDIT_CONTENT</portlet-mode>
      </supports>
      <portlet-info>
         <title>File Portlet</title>
         <keywords>sample,test</keywords>
      </portlet-info>
      <supported-public-render-parameter>uri</supported-public-render-parameter>
      <supported-publishing-event xmlns:x="urn:jboss:portal:content">x:select</supported-publishing-event>
   </portlet>

   <public-render-parameter>
      <identifier>uri</identifier>
      <qname xmlns:c="urn:jboss:portal:content">c:uri</qname>
   </public-render-parameter>

   <event-definition>
      <qname xmlns:x="urn:jboss:portal:content">x:select</qname>
      <value-type>java.lang.String</value-type>
   </event-definition>

</portlet-app>

Note that here we need to use a JSR-286 portlet, this portlet will use the event urn:jboss:portal:content select and have a payload of type java.lang.String. This event will be used to tell the portal the URI selected by the user. This same portlet will also be in charge of rendering the content based on that URI, it will then also need to access the public render parameter qualified with the name: urn:jboss:portal:content uri.

The portlet.xml descriptor

<deployments>
   ...
   <deployment>
      <instance>
         <instance-id>FSContentDrivenPortletInstance</instance-id>
         <portlet-ref>FSContentDrivenPortlet</portlet-ref>
      </instance>
   </deployment>
   ...
</deployments

The portlet-instances.xml descriptor

<web-app>
   ...
   <context-param>
      <param-name>org.jboss.portal.content_type</param-name>
      <param-value>filesystem</param-value>
   </context-param>
   <context-param>
      <param-name>org.jboss.portal.portlet_instance</param-name>
      <param-value>FSContentDrivenPortletInstance</param-value>
   </context-param>
   <listener>
      <listener-class>org.jboss.content.ContentTypeRegistration</listener-class>
   </listener>
   ...
</web-app>

The web.xml descriptor

Warning

You don't need to add the listener class into your war file. As it is provided by the portal it will always be available.

How to create a portlet that will enable configuration of content at runtime has been covered above, however it is also possible to configure content in deployment descriptors. With our previous example it would give the following snippet placed in a *-portal.xml file:

<window>
<window-name>MyWindow</window-name>
<content>
   <content-type>filesystem</content-type>
   <content-uri>/dir1/foo.txt</content-uri>
</content>
<region>center</region>
<height>1</height>
</window>
Final effect - portal window with FSContentDrivenPortlet