Author: atsebro
Date: 2009-04-20 11:41:57 -0400 (Mon, 20 Apr 2009)
New Revision: 13703
Modified:
trunk/docs/realworld_app_guide/en/src/main/docbook/master.xml
trunk/docs/realworld_app_guide/en/src/main/docbook/modules/hiw.xml
Log:
RF-5768: Real World Demo Application Tutorial Update for 3.3.1 release
Modified: trunk/docs/realworld_app_guide/en/src/main/docbook/master.xml
===================================================================
--- trunk/docs/realworld_app_guide/en/src/main/docbook/master.xml 2009-04-20 15:41:34 UTC
(rev 13702)
+++ trunk/docs/realworld_app_guide/en/src/main/docbook/master.xml 2009-04-20 15:41:57 UTC
(rev 13703)
@@ -4,6 +4,7 @@
<!ENTITY intro SYSTEM "modules/intro.xml">
<!ENTITY application_overview SYSTEM
"modules/application_overview.xml">
<!ENTITY getting_started SYSTEM "modules/getting_started.xml">
+ <!ENTITY hiw SYSTEM "modules/hiw.xml">
]>
@@ -32,9 +33,9 @@
</bookinfo>
<toc/>
&intro;
- &application_overview;
+ &application_overview;
&getting_started;
-
+ &hiw;
</book>
Modified: trunk/docs/realworld_app_guide/en/src/main/docbook/modules/hiw.xml
===================================================================
--- trunk/docs/realworld_app_guide/en/src/main/docbook/modules/hiw.xml 2009-04-20 15:41:34
UTC (rev 13702)
+++ trunk/docs/realworld_app_guide/en/src/main/docbook/modules/hiw.xml 2009-04-20 15:41:57
UTC (rev 13703)
@@ -12,9 +12,9 @@
<section>
<title>Used components</title>
- <para>Below there is a list of components used in "Photo
album".</para>
+ <para>Below there is a list of components used in <property>Photo
Album Demo</property>.</para>
<table>
- <title>Components used in "Photo
album"</title>
+ <title>Components used in "Photo Album
Demo"</title>
<tgroup cols="2">
<thead>
<row>
@@ -90,4 +90,323 @@
</table>
</section>
+ <section>
+ <title>Albums representation</title>
+
+ <section>
+ <title>Building the <rich:tree> on the
page</title>
+
+ <para>
+ The <emphasis
role="bold"><property><rich:tree></property></emphasis>
component is designed for hierarchical data presentation and is used to build a tree
structure. The component also supports built-in drag and drop functionality.
+ </para>
+ <para>
+ The <emphasis
role="bold"><property><rich:tree></property></emphasis>
component in the <property>Photo Album Demo</property> application helps to
represent and implement inherently the "Shelves—Albums—Photos"
hierarchy.
+ Shelf is the highest possible level in the tree hierarchy.
+ Shelfs are used to group thematic albums and may contain as many
albums as needed.
+ Photos are not represented in the tree because it can be a great
number of them and it can make a tree clumsy.
+ Photos are rendered in the center of the screen (hereinafter
referred to as a watching area).
+ </para>
+
+ <para>
+ Implicitly, the <emphasis
role="bold"><property><rich:tree></property></emphasis>
component takes one the main place in the <property>Photo Album
Demo</property> and is tightly bounded with the application logic.
+ There are several ways to implement the <emphasis
role="bold"><property><rich:tree></property></emphasis>.
+ In the current application the <emphasis
role="bold"><property><rich:tree></property></emphasis>
is designed using a model tag <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>.
+ </para>
+ <para>
+ The <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>
component accepts a collection of elements, which are allowed to include lists, arrays,
maps, XML NodeList or NamedNodeMap, and iterates through it.
+ The <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>
component repeats a hierarchical tree structure on a <code>xhtml</code> or
<code>jsp</code> page in a component tree and can be nested without any
limitations.
+ The code snippet below schematically shows the idea of how a tree
can be built on a page with the help of adaptors:
+ </para>
+
+ <programlisting
role="XML"><![CDATA[<rich:tree>
+ <rich:treeNodesAdaptor>
+ <rich:treeNode />
+
+ <rich:treeNodesAdaptor>
+ <rich:treeNode />
+
+ <rich:treeNodesAdaptor>
+ <rich:treeNode />
+ ...
+ </rich:treeNodesAdaptor>
+ </rich:treeNodesAdaptor>
+ </rich:treeNodesAdaptor>
+</rich:tree>]]></programlisting>
+
+ <para>
+ When using <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>
component there is no need to specify
+ the
<emphasis><property>"value"</property></emphasis>
and
<emphasis><property>"var"</property></emphasis>
attributes for the <emphasis
role="bold"><property><rich:tree></property></emphasis>.
+ The values for nodes to render are passed directly into the
corresponding adaptor and the component performs all the necessary iterative work
+ (vizit the <ulink
url="http://livedemo.exadel.com/richfaces-demo/richfaces/treeNodesAd...
page</ulink> on the RichFacesLiveDemo for more details).
+ </para>
+
+ <para>
+ Implementation of the <emphasis
role="bold"><property><rich:tree></property></emphasis>
in the application is very close to the model shown above.
+ The <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>
component has <nodes> attribute.
+ The top <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>
in the <emphasis
role="bold"><property><rich:tree></property></emphasis>
in the Phot Album Demo application is responsible for shelfs rendering.
+ Its
<emphasis><property>"nodes"</property></emphasis>
attribute refers to
<emphasis><property>getShelfs()</property></emphasis> method of
the <code>ShelfManager</code> class and gets the collection of shelfs
associated with the current user including all shared shelfs in the system.
+ Take a look at this method:
+ </para>
+
+ <programlisting role="JAVA"><![CDATA[public
List<Shelf> getShelfs(){
+ if(shelfs == null){
+ shelfs = shelfAction.getShelfs(user);
+ }
+ return shelfs;
+} ]]></programlisting>
+
+ <para>
+ After the
<emphasis><property>"nodes"</property></emphasis>
attribute of the <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>,
which is responsible for shelves rendering, receives the collection of shelves,
+ the iteration process switches to the nested <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>,
which is responsible for albums.
+ The "albums" <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>
<emphasis><property>"nodes"</property></emphasis>
attribute refers in its turn to the <code>albums</code> field of the
<code>Shelf</code> class
+ and takes a collection of all albums associated with the current
shelf.
+ The "albums" <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>
renders all albums that belong to the current iterating shelf and then switches back to
the "shelf" <emphasis
role="bold"><property><rich:treeNodesAdaptor></property></emphasis>
to render and iterate the next shelf in the shelves collection received earlier.
+ Here is how it looks in the
<code>webapp/includes/index/tree.xhtml</code> file:
+ </para>
+
+ <programlisting role="XML"><![CDATA[<rich:tree
id="tree" switchType="client" treeNodeVar="treeNode"
showConnectingLines="false" dragIndicator="dragIndicator"
ajaxSubmitSelection="false"
+ adviseNodeOpened="#{treeManager.adviseNodeSelected}"
+ adviseNodeSelected="#{treeManager.adviseNodeSelected}"
+ iconCollapsed="/img/shell/tree_icon_plus.png"
+ iconExpanded="/img/shell/tree_icon_minus.png">
+ <rich:treeNodesAdaptor nodes="#{shelfManager.getShelfs()}"
var="shelf">
+ <rich:treeNode reRender="mainArea"
selectedClass="tree-selected-node">
+ <f:facet name="icon">
+ <h:graphicImage style="border: none"
value="/img/shell/tree_icon_shelf.png">
+ <a4j:support reRender="tree, mainArea"
event="onclick" actionListener="#{controller.showShelf(shelf)}"
similarityGroupingId="sel" />
+ </h:graphicImage>
+ </f:facet>
+ <rich:dropSupport id="shelfDND"
acceptedTypes="album" dropValue="#{shelf}"
dropListener="#{dndManager.processDrop}" reRender="mainArea, tree"
/>
+ <ui:include src="/includes/contextMenu/CMForShelf.xhtml"
>
+ <ui:param name="shelf" value="#{shelf}"
/>
+ </ui:include>
+ <a4j:outputPanel>
+ <h:outputText value="#{shelf.name}" />
+ <h:outputText value=" :: " />
+ <strong>#{shelf.unvisitedImages.size()}</strong> new
+ <a4j:support reRender="tree, mainArea"
event="onclick" actionListener="#{controller.showShelf(shelf)}"
similarityGroupingId="sel" />
+ </a4j:outputPanel>
+ </rich:treeNode>
+
+ <rich:treeNodesAdaptor var="album"
nodes="#{shelf.albums}">
+ <rich:treeNode reRender="mainArea"
dragType="album" dragValue="#{album}" dropValue="#{album}"
acceptedTypes="image, album"
+ selectedClass="tree-selected-node"
icon="img/shell/tree_icon_album.png">
+ <f:facet name="iconLeaf">
+ <h:graphicImage style="border: none"
value="img/shell/tree_icon_album.png">
+ <a4j:support reRender="tree, mainArea"
event="onclick" actionListener="#{controller.showAlbum(album)}"
similarityGroupingId="sel" />
+ </h:graphicImage>
+ </f:facet>
+ <ui:include
src="/includes/contextMenu/CMForAlbum.xhtml" >
+ <ui:param name="album"
value="#{album}" />
+ </ui:include>
+ <rich:dndParam name="label" type="drag"
value="#{album.name}" />
+ <a4j:outputPanel>
+ <h:outputText value="#{album.name}" />
+ <h:outputText value=" :: " />
+
<strong>#{album.unvisitedImages.size()}</strong> new
+ <a4j:support reRender="tree, mainArea"
event="onclick" actionListener="#{controller.showAlbum(album)}"
similarityGroupingId="sel" />
+ </a4j:outputPanel>
+ <rich:dropSupport id="php"
acceptedTypes="image" dropValue="#{album}"
dropListener="#{dndManager.processDrop}" reRender="mainArea, tree"
/>
+ </rich:treeNode>
+ </rich:treeNodesAdaptor>
+ </rich:treeNodesAdaptor>
+</rich:tree>]]></programlisting>
+
+ <para>
+ The illustration below shows how the Shelves—Albums heirarchy is
rendered on the page.
+ </para>
+
+ <figure>
+ <title>Shelves and albums nodes rendered with the help of
the <rich:treeNodesAdaptor></title>
+ <mediaobject>
+ <imageobject>
+ <imagedata
fileref="images/tree.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+</section>
+
+ <section>
+ <title>Drag-and-drop inside the
<rich:tree></title>
+ <para>
+ Drag and drop features supported in the Photo Album Demo
application are not so complicated as it may seem from the first view.
+ In this application we can mark out two types of drag-and-drop:
one type takes place only inside the tree (between tree nodes) and another one — between
the watching area and the tree.
+ The difference is not considerable enough to describe two types
separately, but also not at all insignificant to be omitted here.
+ </para>
+
+ <para>
+ Let's examine drag-and-drop inside tree. The tree
related components (<emphasis
role="bold"><property><rich:tree></property></emphasis>
and <emphasis
role="bold"><property><rich:treeNode></property></emphasis>)
+ have their own attributes that provide drag-and-drop
functionality. These attributes can be divided into two groups: those which provide drag
(dragValue, dragListener, dragIndicator, dragType attributes) and those which provide drop
operations (dropValue, dropListener, acceptedTypes, typeMapping).
+ </para>
+
+ <note>
+ <title>
+ Note:
+ </title>
+ <para>
+ Due to "Shelves—Albums—Photos" paradigm
we can say that photos could be moved between albums, albums could be moved between
shelves.
+ To avoid a mishmash, it's not allowed to place photos
directly in shelves as well as nesting shelves inside shelves or albums inside albums.
+ </para>
+ </note>
+
+ <para>
+ All albums or images (<property>drag-and-drop
zones</property> in terms of RichFaces drag-and-drop), which are assumed to be
dragged, must be marked somehow in the application code.
+ For albums that are represented as tree nodes we will use
previously mentioned <property>drag group</property> attributes:
+ </para>
+ <programlisting
role="XML"><![CDATA[<rich:treeNodesAdaptor var="album"
nodes="#{shelf.albums}">
+ <rich:treeNode dragType="album"
+ dragValue="#{album}"
+ dropValue="#{album}"
+ acceptedTypes="image, album" />
+ …
+</rich:treeNodesAdaptor>
+]]></programlisting>
+
+ <para>
+ To provide drop functionality for the marked albums we should mark
shelves as drop zones in the application code too.
+ For this purpose we add the <emphasis
role="bold"><property>rich:dropSupport</property></emphasis>
component to the "shelf" node:
+ </para>
+ <programlisting
role="XML"><![CDATA[<rich:treeNodesAdaptor
nodes="#{shelfManager.getShelfs()}" var="shelf">
+ <rich:treeNode
+ <rich:dropSupport id="shelfDND"
+ acceptedTypes="album"
+ dropValue="#{album}"
+ dropListener="#{dndManager.processDrop}"
+ reRender="mainArea">
+ </rich:dropSupport>
+ …
+ </rich:treeNode>
+</rich:treeNodeAdaptor>]]></programlisting>
+
+ <para>
+ The
<emphasis><property>"acceptedType"</property></emphasis>
attribute tells the "shelf" node what types of dragged zones (albums in
this case) it can accept.
+ The value for the
<emphasis><property>"acceptedType"</property></emphasis>
attribute corresponds the album
<emphasis><property>"dragType"</property></emphasis>
attribute.
+ The method binding that will process drag-and-drop operation should
be pointed via
<emphasis><property>"dropListener"</property></emphasis>
attribute of the <emphasis
role="bold"><property>rich:tree</property></emphasis>.
+ This method is shown in th e listing below:
+ </para>
+ <programlisting role="JAVA"><![CDATA[...
+public void processDrop(DropEvent dropEvent) {
+ Dropzone dropzone = (Dropzone) dropEvent.getComponent();
+ Object dragValue = dropEvent.getDragValue();
+ Object dropValue = dropzone.getDropValue();
+ if(dragValue instanceof Image){
+ if(!((Album)dropValue).getOwner().getLogin().equals(user.getLogin())){
+ Events.instance().raiseEvent(Constants.ADD_ERROR_EVENT,
Constants.DND_PHOTO_ERROR);
+ return;
+ }
+ handleImage((Image)dragValue, (Album)dropValue);
+ }else if(dragValue instanceof Album){
+ if(!((Shelf)dropValue).getOwner().getLogin().equals(user.getLogin())){
+ Events.instance().raiseEvent(Constants.ADD_ERROR_EVENT,
Constants.DND_ALBUM_ERROR);
+ return;
+ }
+ handleAlbum((Album)dragValue, (Shelf)dropValue);
+ }
+}
+...]]></programlisting>
+ <para>
+ The illustration below shows how the described above drag-and-drop
features are rendered in the Photo Album Demo.
+ </para>
+ <figure>
+ <title>Dragging the "Flora" album from
"Sport" shelf into the "Nature" (left) and the tree
after drag-and-drop (right).</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata
fileref="images/dnd.png"/>
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ </section>
+
+ </section>
+
+ <section>
+ <title>Upload images</title>
+ <para>The implementation of <emphasis
role="bold"><property><rich:fileUpload></property></emphasis>
in the Phot Album Demo uses the embedded Flash module that adds extra functionality to the
component.
+ Here are the additional features that the Flash module provides:
+ </para>
+ <itemizedlist>
+ <listitem><para>Multiple files
choosing;</para></listitem>
+ <listitem><para>Specification of permitted file types in
the "Open File" dialog window;</para></listitem>
+ <listitem><para>A number of additional entry object
properties.</para></listitem>
+ </itemizedlist>
+
+ <para>
+ The photos uploading functionality is realized on the
<code>/includes/fileUpload/fileUploader.xhtml page</code>. Let's have a
look at this page to find out how the uploader is imlemented:
+ </para>
+
+ <programlisting role="XML"><![CDATA[<rich:fileUpload
style="margin : 0px 0px 20px 0px; width : 504px; height : 200px; background :
#f1f1f1; border : 1px solid #A1A1A1"
+ id="fileUpload"
+ allowFlash="true"
+ immediateUpload="false"
+ acceptedTypes="jpg,jpeg"
+ maxFilesQuantity="100"
+ autoclear="true"
+ fileUploadListener="#{fileUploadManager.listener}" >
+ <a4j:support event="onuploadcomplete" reRender="filesPanel, tree"
/>
+ <a4j:support event="onfileuploadcomplete" />
+ </rich:fileUpload>]]></programlisting>
+
+ <para>
+ The
"<emphasis><property>FileUploadListener</property></emphasis>"
attribute is binded with <code>fileUploadManager.listener</code> method which
makes the main job on the upload.
+ Below is the <code>fileUploadManager.listener</code>
method:
+ </para>
+ <programlisting role="JAVA"><![CDATA[public void
listener(UploadEvent event) throws Exception {
+ UploadItem item = event.getUploadItem();
+ Image image = constructImage(item);
+ try {
+ extractMetadata(item, image);
+ } catch (Exception e1) {
+ addError(item, image, Constants.FILE_PROCESSING_ERROR);
+ return;
+ }
+ image.setAlbum(model.getSelectedAlbum());
+ if(image.getAlbum() == null){
+ addError(item, image, Constants.NO_ALBUM_TO_DOWNLOAD_ERROR);
+ return;
+ }
+ try{
+ if(imageAction.isImageWithThisPathExist(image)){
+ image.setPath(generateNewPath(image.getPath()));
+ }
+ imageAction.addImage(image);
+ }catch(Exception e){
+ addError(item, image, Constants.IMAGE_SAVING_ERROR);
+ return;
+ }
+ if(!fileManager.addImage(image.getFullPath(), item.getFile().getPath())){
+ addError(item, image, Constants.FILE_SAVE_ERROR);
+ return;
+ }
+ fileWrapper.getFiles().add(image);
+ Events.instance().raiseEvent(Constants.IMAGE_ADDED_EVENT, image);
+ item.getFile().delete();
+}]]></programlisting>
+
+<para>
+ When a photo is added into the uploader, the first thing it does is saving this
photo in the file system.
+ The uploaded files are stored in the temporary folder in the computer file system.
+ For this purpose the value of the <code>createTempFile</code>
parameter in <code>Ajax4jsf Filter</code> section should be set to
<code>true</code>.
+ Below in the <code>Web.xml</code> file Ajax filter section:
+</para>
+
+ <programlisting role="XML"><![CDATA[...
+<init-param>
+ <param-name>createTempFiles</param-name>
+ <param-value>true</param-value>
+</init-param>
+...]]></programlisting>
+
+ <para>
+ Then the uploader creates an <code>Image</code> object and
extracts all image metadata such as Camera name, Image size etc.
+ Then it sets an album and generates a new path to it.
+ The system should save six different sizes of the photo.
+ After the photo was added into the data base the system removes a temporary
file created for storage.
+ </para>
+
+
+ </section>
+
+
</chapter>