Author: julien(a)jboss.com
Date: 2007-06-15 08:02:00 -0400 (Fri, 15 Jun 2007)
New Revision: 7435
Removed:
docs/trunk/referenceGuide/en/modules/contentIntegration.xml
Log:
renaming contentIntegration to contentintegration
Deleted: docs/trunk/referenceGuide/en/modules/contentIntegration.xml
===================================================================
--- docs/trunk/referenceGuide/en/modules/contentIntegration.xml 2007-06-15 10:26:05 UTC
(rev 7434)
+++ docs/trunk/referenceGuide/en/modules/contentIntegration.xml 2007-06-15 12:02:00 UTC
(rev 7435)
@@ -1,451 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<chapter id="contentIntegration">
- <chapterinfo>
- <author>
- <firstname>Julien</firstname>
- <surname>Viet</surname>
- <email>julien @ jboss dot com</email>
- </author>
- </chapterinfo>
- <title>Content Integration</title>
- <para>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
- removing the need to configure a portlet for that purpose.</para>
- <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.</note>
- <mediaobject>
- <imageobject>
- <imagedata align="center"
fileref="images/content/before.png" format="png"/>
- </imageobject>
- <caption>
- <para>The portal uses portlets to configure content</para>
- </caption>
- </mediaobject>
- <mediaobject>
- <imageobject>
- <imagedata align="center"
fileref="images/content/after.png" format="png"/>
- </imageobject>
- <caption>
- <para>The portal references directly the content and use portlet to
interact with content</para>
- </caption>
- </mediaobject>
- <sect1>
- <title>Window content</title>
- <para>The content of a window is defined by
- <itemizedlist>
- <listitem>The content URI which is the resource that the window is
pointing to. It is an arbitrary string that
- the portal cannot interpret and is left up to the content provider to
interpret.</listitem>
- <listitem>The window content type which defines how the portal
interpret the window content
- <itemizedlist>
- <listitem>The default content type is for portlets and has the
value <emphasis>portlet</emphasis>. For that
- content type, the content URI is the portlet instance
id.</listitem>
- <listitem>The CMS content type allows to integrate content from
the CMS at the page and it has the value
- <emphasis>cms</emphasis>. For that content type, the
content URI is the CMS file path.</listitem>
- </itemizedlist>
- </listitem>
- <listitem>The content parameters which is a set of additional key/value
string pairs holding state that is interpreted
- by the content provider.</listitem>
- </itemizedlist>
- </para>
- <para>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 168 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.</para>
- </sect1>
- <sect1>
- <title>Content customization</title>
- <para>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 168 Portlet. For that purpose two special portlet modes
called
- <emphasis>edit_content</emphasis> and
<emphasis>select_content</emphasis> has been introduced. It signals to the
portlet
- that it is selecting or editing the content portion of the state of a portlet.
<emphasis>select_content</emphasis> is
- used to select a new content to put in a window while
<emphasis>edit_content</emphasis> 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 targetted to configure how the portlet show content to the end user rather
than what content it shows.</para>
- <imageobject>
- <imagedata align="center"
fileref="images/content/cms.png" format="png"/>
- </imageobject>
- <caption>Example of content customization - CMS Portlet</caption>
- </sect1>
- <sect1>
- <title>Content Driven Portlet</title>
- <para>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.
- </para>
- <sect2>
- <title>Displaying content</title>
- <para>At runtime the portal will call the portlet with the view mode when
it displays content. It will send to the
- portlet the information about the content to display using the render
parameters. Therefore the portlet has
- just to read the render parameters and use them to properly display the content
in the portlet. The render parameters
- values are the key/value pairs that forms the content properties and the
resource URI is found under the <emphasis>uri</emphasis>
- parameter name.</para>
- </sect2>
- <sect2>
- <title>Configuring content</title>
- <para>As explained before, the portal will call the portlet using the
<emphasis>edit_content</emphasis> mode.
- In that mode the portlet and the portal will communicate using either action or
render parameters. We have two use cases
- which are:
- <itemizedlist>
- <listitem>The portal needs to configure a new content item for a new
window. In that use case the portal will not send special
- render parameters to the portlet and the initial set of render parameters
will be empty. The portlet can
- then use render parameters in order to provide navigation in the content
repository. For example the portlet
- can navigate the CMS tree and store the current CMS path in the render
parameters. Whenever the portlet has decided
- to tell the portal that content has been selected by the user it needs to
use an action URL with a special set of
- parameters:
- <itemizedlist>
-
<listitem><emphasis>content.action.select</emphasis> equals to any
value</listitem>
- <listitem><emphasis>content.uri</emphasis> equals
to the content URI</listitem>
- <listitem><emphasis>content.param.</emphasis> used
as prefix to configure content parameters</listitem>
- </itemizedlist>
- </listitem>
- <listitem>The second use case happens when the portal needs to edit
existing content. In such situation
- everything works as explained before except that the initial set of render
parameters of the portlet
- will be prepopulated with the content uri URI and
parameters.</listitem>
- </itemizedlist>
- </para>
- </sect2>
- <sect2>
- <title>Step by step example of a content driven portlet</title>
- <para></para>
- <sect3>
- <title>The Portlet skeleton</title>
- <para>Here is the base skeleton of the content portlet. The
FSContentDrivenPortlet shows the files which are
- in the war file in which the portlet is deployed. The arbitrary name
<emphasis>filesystem</emphasis>
- will be the content type interpreted by the portlet.
- </para>
- <programlisting><![CDATA[
-public class FSContentDrivenPortlet extends GenericPortlet
-{
-
- /** The edit_content mode. */
- public static final PortletMode EDIT_CONTENT_MODE = new
PortletMode("edit_content");
-
- /** The select_content mode. */
- public static final PortletMode SELECT_CONTENT_MODE = new
PortletMode("select_content");
-
- ...
-
-}
-]]></programlisting>
- </sect3>
- <sect3>
- <title>Overriding the dispatch method</title>
- <para>First the <emphasis>doDispatch(RenderRequest req,
RenderResponse resp)</emphasis> is overriden in order
- to branch the requeset flow to a method that will take care of displaying the
editor.</para>
- <programlisting><![CDATA[
-protected void doDispatch(RenderRequest req, RenderResponse resp)
- throws PortletException, PortletSecurityException, IOException
-{
- if (EDIT_CONTENT_MODE.equals(req.getPortletMode()) ||
SELECT_CONTENT_MODE.equals(req.getPortletMode()))
- {
- doEditContent(req, resp);
- }
- else
- {
- super.doDispatch(req, resp);
- }
-}
-]]></programlisting>
- </sect3>
- <sect3>
- <title>Utilities methods</title>
- <para>The portlet also needs a few utilities methods which take care of
converting content URI to a file
- back and forth. There is also an implementation of a file filter that keep
only text files and avoid the
- WEB-INF directory of the war file for security reasons.</para>
- <programlisting><![CDATA[
-protected File getFile(String contentURI) throws IOException
-{
- String realPath = getPortletContext().getRealPath(contentURI);
- if (realPath == null)
- {
- throw new IOException("Cannot access war file content");
- }
- File file = new File(realPath);
- if (!file.exists())
- {
- throw new IOException("File " + contentURI + " does not
exist");
- }
- return file;
-}
-]]></programlisting>
- <programlisting><![CDATA[
- protected String getContentURI(File file) throws IOException
- {
- String rootPath = getPortletContext().getRealPath("/");
- if (rootPath == null)
- {
- throw new IOException("Cannot access war file content");
- }
-
- // Make it canonical
- rootPath = new File(rootPath).getCanonicalPath();
-
- // Get the portion of the path that is significant for us
- String filePath = file.getCanonicalPath();
- return filePath.length() >=
- rootPath.length() ? filePath.substring(rootPath.length()) : null;
- }
-]]></programlisting>
- <programlisting><![CDATA[
- private final FileFilter filter = new FileFilter()
- {
- public boolean accept(File file)
- {
- String name = file.getName();
- if (file.isDirectory())
- {
- return !"WEB-INF".equals(name);
- }
- else if (file.isFile())
- {
- return name.endsWith(".txt");
- }
- else
- {
- return false;
- }
- }
- };
-]]></programlisting>
- </sect3>
- <sect3>
- <title>The editor</title>
- <para>The editor is probably the longest part of the portlet. It tries
to stay simple though and goes directly
- to the point.</para>
- <imageobject>
- <imagedata align="center"
fileref="images/content/fs1.png" format="png"/>
- </imageobject>
- <caption>Content editor of FSContentDrivenPortlet in
action</caption>
- <programlisting><![CDATA[
-protected void doEditContent(RenderRequest req, RenderResponse resp)
- throws PortletException, PortletSecurityException, IOException
-{
- // Get the uri value optionally provided by the portal
- String uri = req.getParameter("content.uri");
-
- // Get the working directory directory
- File workingDir;
- if (uri != null)
- {
- workingDir = getFile(uri).getParentFile();
- }
- 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("content.uri", getContentURI(child));
- writer.print("<li><a href=\"" + selectFileURL +
"\">" + child.getName() +
- "</a></li>");
- }
- }
- writer.print("</ul><br/>");
-
- //
- writer.close();
-}
-]]></programlisting>
- </sect3>
- <sect3>
- <title>Viewing content at runtime</title>
- <para>Last but not least the portlet needs to implement the
<emphasis>doView(RenderRequest req, RenderResponse resp)</emphasis>
- method in order to display the file that the portal window wants to
show.</para>
- <programlisting><![CDATA[
-protected void doView(RenderRequest req, RenderResponse resp)
- throws PortletException, PortletSecurityException, IOException
-{
- // Get the URI provided by the portal
- String uri = req.getParameter("uri");
-
- // Configure the response
- resp.setContentType("text/html");
- PrintWriter writer = resp.getWriter();
-
- //
- if (uri == null)
- {
- writer.print("No selected file");
- }
- else
- {
- File file = getFile(uri);
- FileInputStream in = null;
- try
- {
- in = new FileInputStream(file);
- FileChannel channel = in.getChannel();
- byte[] bytes = new byte[(int)channel.size()];
- ByteBuffer buffer = ByteBuffer.wrap(bytes);
- channel.read(buffer);
- writer.write(new String(bytes, 0, bytes.length, "UTF8"));
- }
- catch (FileNotFoundException e)
- {
- writer.print("No such file " + uri);
- getPortletContext().log("Cannot find file " + uri, e);
- }
- finally
- {
- if (in != null)
- {
- in.close();
- }
- }
- }
-
- //
- writer.close();
-}
-]]></programlisting>
- </sect3>
- <sect3>
- <title>Hooking the portlet into the portal</title>
- <imageobject>
- <imagedata align="center"
fileref="images/content/fs2.png" format="png"/>
- </imageobject>
- <caption>Management portlet with
<emphasis>filesystem</emphasis> content type enabled</caption>
- <para>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 <emphasis>portlet.xml</emphasis>
descriptor will define our portlet, the
- <emphasis>portlet-instances.xml</emphasis> will create a single
instance of our portlet. The
- <emphasis>web.xml</emphasis> descriptor will contain a servlet
context listener that will hook the content
- type in the portal content type registry.</para>
- <programlisting><![CDATA[
-<?xml version="1.0" encoding="UTF-8"?>
-<portlet-app
-
xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1...
-
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
- version="1.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.portlet.test.FSContentDrivenPortlet</portlet-class>
- <supports>
- <mime-type>text/html</mime-type>
- </supports>
- <portlet-info>
- <title>File Portlet</title>
- <keywords>sample,test</keywords>
- </portlet-info>
- </portlet>
- ...
-</portlet-app>
-]]></programlisting>
- <para>The portlet.xml descriptor</para>
- <programlisting><![CDATA[
-<deployments>
- ...
- <deployment>
- <instance>
- <instance-id>FSContentDrivenPortletInstance</instance-id>
- <portlet-ref>FSContentDrivenPortlet</portlet-ref>
- </instance>
- </deployment>
- ...
-</deployments
-]]></programlisting>
- <para>The portlet-instances.xml descriptor</para>
- <programlisting><![CDATA[
-<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>
-]]></programlisting>
- <para>The web.xml descriptor</para>
- <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.</warning>
- </sect3>
- </sect2>
- </sect1>
- <sect1>
- <title>Configuring window content in deployment descriptor</title>
- <para>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 <emphasis>*-portal.xml</emphasis>
file:
- </para>
- <programlisting><![CDATA[
-<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>
-]]></programlisting>
- <imageobject>
- <imagedata align="center"
fileref="images/content/fs3.png" format="png"/>
- </imageobject>
- <caption>Final effect - portal window with
FSContentDrivenPortlet</caption>
- <note>How to configure CMS file this way is covered in the CMS chapter:
<xref linkend="configuration-cms_content"/></note>
- </sect1>
-</chapter>