Author: julien(a)jboss.com
Date: 2007-03-21 14:56:43 -0400 (Wed, 21 Mar 2007)
New Revision: 6791
Modified:
docs/trunk/referenceGuide/en/modules/contentIntegration.xml
Log:
improved the content integration chapter
Modified: docs/trunk/referenceGuide/en/modules/contentIntegration.xml
===================================================================
--- docs/trunk/referenceGuide/en/modules/contentIntegration.xml 2007-03-21 18:22:58 UTC
(rev 6790)
+++ docs/trunk/referenceGuide/en/modules/contentIntegration.xml 2007-03-21 18:56:43 UTC
(rev 6791)
@@ -85,54 +85,297 @@
</para>
</sect2>
<sect2>
- <title>Example</title>
+ <title>Step by step example of a content driven portlet</title>
<para></para>
- <programlisting><![CDATA[
-
-public class FileContentPortlet extends GenericPortlet
+ <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");
- /**
- * Additional dispatch for the edit content mode.
- */
- protected void doDispatch(RenderRequest req, RenderResponse resp) throws
PortletException, PortletSecurityException, IOException
+ ...
+
+}
+]]></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()))
{
- if (EDIT_CONTENT.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)
{
- doEditContent(req, resp);
+ throw new IOException("Cannot access war file content");
}
- else
+
+ // 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)
{
- super.doDispatch(req, resp);
+ 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>
+ <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);
+ }
- protected void doEditContent(RenderRequest req, RenderResponse resp) throws
PortletException, PortletSecurityException, IOException
+ // 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)
{
- // Get the uri value either provided by the portal or by ourself
- String uri = req.getParameter("content.uri");
- File root = null;
- if (uri == 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())
{
- root = "/";
+ choseDirURL.setParameter("current_dir", getContentURI(child));
+ writer.print("<li><a href=\"" + choseDirURL +
"\">" + child.getName() + "</a></li>");
}
- else
+ }
+ 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())
{
- root = new File(uri).getParentFile().getCanonicalPath();
+ selectFileURL.setParameter("content.uri", getContentURI(child));
+ writer.print("<li><a href=\"" + selectFileURL +
"\">" + child.getName() + "</a></li>");
}
+ }
+ writer.print("</ul><br/>");
- // Get the children of the selected file
- File fic = new File(uri);
- File[] children = fic.listFiles();
+ //
+ 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>
+ <para>Finally we need to make the portal aware of the fact that the
portlet can edit and interpret. For that
+ we need various 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 and finally 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.portal.core.servlet.jsp.ContentTypeRegistration</listener-class>
+ </listener>
+ ...
+</web-app>
+]]></programlisting>
+ <para>The web.xml descriptor</para>
+ </sect3>
</sect2>
</sect1>
</chapter>