Chapter 3. The [fleXive] Tutorial

Table of Contents

Your first [fleXive] application
Defining the data model
Retrieving data from the database
Building the graphical user interface
Deployment descriptor and JSF configuration
Compiling and deploying the application
Preview of the Backend Administration
Tutorial 1: The Document Store Application
Defining the data model
The document browser and upload pages
Using <fx:resultValue>
Passing content instances to the editor form
The upload form
Retrieving data from the database
Rendering previews: the ThumbnailServlet
Wiring up the faces configuration
Compiling and deploying the application

For your first [fleXive] application, we assume you have a flexive installation up and running on your local or on a remote machine. If not, follow the instructions in Chapter 2, Installing [fleXive] . The complete source code can be found in [fleXive] source packages or in the subversion repository under src/examples.

Our first [fleXive] application implements a very simple blogging system with an input mask and a view for the submitted entries. Looking at the source directory of the application, we find the following directory structure:

/helloworld/
|
+--build.xml

/helloworld/java/
/helloworld/java/com.flexive.examples.helloworld.war
|
+--HelloWorldBean.java

/helloworld/resources/
/helloworld/resources/scripts/
/helloworld/resources/scripts/library/
/helloworld/resources/scripts/startup/
/helloworld/resources/scripts/runonce/
|
+--hello001.groovy


/helloworld/web/
|
+--create.xhtml
+--index.xhtml

/helloworld/web/WEB-INF/
|
+--faces-config.xml
+--web.xml    

For the web interface of the application we use JSF 1.2, using Facelets for creating the JSF views (i.e. we use plain XHTML templates instead of JSP). [fleXive] includes components for rendering and editing [fleXive] contents in JSF applications, although you could also use other web framework like Struts or Tapestry - you'd just miss the convenient UI components that allow a rapid creation of web applications based on [fleXive].

If you are not familiar with JSF tag libraries please refer to the Tag Library Documentation or try the JSF section of the Java EE 5 Tutorial.

The main page renders all available blog entries and shows a link to a form for creating new entries. Facelets' <ui:repeat/> tag is used to iterate over the rows of the datamodel returned by the JSF bean we created in the previous section. A row of the datamodel provides indexed access to the columns selected in the search query of the previous section. In this case, #{columns[0]} would be the content primary key (@pk), #{columns[1]} returns the entry title, and so on. The source for this file can be found under web/index.xhtml.

                <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:c="http://java.sun.com/jstl/core"
      xmlns:fx="http://www.flexive.com/jsf/core">
<head>
    <fx:includes/>
</head>

<body>

<h:outputLink value="create.xhtml">Create a new entry</h:outputLink>

<!-- Render available blog postings, as returned by helloWorldBean.blogEntries -->

<!-- The Facelets ui:repeat tag is used to iterate over arrays, lists and JSF datamodels -->
<ui:repeat value="#{helloWorldBean.blogEntries}" var="column">
    <h3>
        <!-- Entry title. Access the value of each column through the expression language
         and the column index -->
        #{column[1]}
    </h3>
        <pre>#{column[2]} <!-- Entry text -->

            <i>#{column[3]}</i> <!-- Creation date -->
        </pre>
</ui:repeat>

<p><h:outputLink
        onclick="window.open('http://wiki.flexive.org/confluence/display/FX/Listing+blog+entries', 'In_depth_explanation', 'width=950,height=600,left=50,top=200,scrollbars=yes,resizable=yes');"
        value="#">
    What happens on this page?
</h:outputLink>
</p>

</body>

</html>
            

The input form for creating new postings uses the <fx:content/> and <fx:value/> components provided by [fleXive] to create a simple input form for [fleXive] contents. All you need to provide is the name of the type you want to use as template (blogEntry) and the references to the properties to be rendered (entryTitle, entryText). Finally, a JSF command link is used to render a button for saving the entered data. The save command is executed by a [fleXive] system bean, fxContentViewBean.

                <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:c="http://java.sun.com/jstl/core"
      xmlns:fx="http://www.flexive.com/jsf/core">
<head>
    <title>Flexive Helloworld Application</title>
    <fx:includes/>
</head>

<body>

<h:form>
    <!-- Display all JSF messages -->
    <h:messages/>

    <h:outputLink value="index.xhtml">Back to blog</h:outputLink>

    <!-- The fx:content tag references our type "Blog Entry" -->
    <fx:content typeName="blogEntry" var="entry">

        <!-- This renders an html input field for the type's property "Entry Title" -->
        <fx:value property="entryTitle"/>

        <!-- This renders an html input field for the type's property "Entry Text" -->
        <fx:value property="entryText"/>

        <!-- Save content using the FxContentViewBean, pass the content instance
             stored in component_content via f:setPropertyActionListener -->
        <h:commandLink action="#{fxContentViewBean.save}">
            <f:setPropertyActionListener target="#{fxContentViewBean.content}" value="#{entry_content}"/>
            Publish
        </h:commandLink>

    </fx:content>
</h:form>

<p><h:outputLink
        onclick="window.open('http://wiki.flexive.org/confluence/display/FX/Creating+a+blog+entry', 'In_depth_explanation', 'width=950,height=600,left=50,top=200,scrollbars=yes,resizable=yes');"
        value="#">
    What happens on this page?
</h:outputLink>
</p>

</body>
</html>
            

In the web/WEB-INF directory there are two files:

  • The web deployment descriptor in web.xml. Here we initialize the JSF runtime and add the FxFilter for pages handled by [fleXive]. FxFilter is required for more advanced [fleXive] functionality, but is not required for this application.

                                <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    		  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
               version="2.5">
    
        <!-- Use Documents Saved as *.xhtml -->
        <context-param>
            <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
            <param-value>.xhtml</param-value>
        </context-param>
    
        <!-- Configure FxFilter -->
        <filter>
            <filter-name>FxFilter</filter-name>
            <filter-class>com.flexive.war.filter.FxFilter</filter-class>
        </filter>
    
        <filter-mapping>
            <filter-name>FxFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <!-- Configure Faces servlet -->
        <servlet>
            <servlet-name>Faces Servlet</servlet-name>
            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>*.xhtml</url-pattern>
        </servlet-mapping>
        <!--
            /faces/* (or another suffix pattern) should always be the last url-pattern for the FacesServlet, 
            otherwise the flexive Weblets includes won't work
        -->
        <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>/faces/*</url-pattern>
        </servlet-mapping>
    
        <welcome-file-list>
            <welcome-file>index.xhtml</welcome-file>
        </welcome-file-list>
    
        <listener>
            <listener-class>net.java.dev.weblets.WebletsContextListener</listener-class>
        </listener>
        <listener>
            <listener-class>com.flexive.war.listener.SessionTimeoutListener</listener-class>
        </listener>
    </web-app>
    
                            
  • The JSF configuration file in faces-config.xml. Here we register the HelloWorldBean and provide navigation rules between the overview and the create page.

                                <?xml version='1.0' encoding='UTF-8'?>
    <faces-config xmlns="http://java.sun.com/xml/ns/javaee"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
                  version="1.2">
    
        <!-- Facelets View Handler Definition -->
        <application>
            <view-handler>
                com.sun.facelets.FaceletViewHandler
            </view-handler>
        </application>
    
        <!-- Definition of the managed bean which retrieves the data from database -->
        <managed-bean>
            <managed-bean-name>helloWorldBean</managed-bean-name>
            <managed-bean-class>com.flexive.examples.helloworld.war.HelloWorldBean</managed-bean-class>
            <managed-bean-scope>request</managed-bean-scope>
        </managed-bean>
    
        <!--  A navigation rule for our input mask, if everything goes right,
         "success" is returned, which leads to a direct rendering and response
         of the index.xhtml view. The entries made via the input mask are shown
         in this view. -->
        <navigation-rule>
            <from-view-id>/create.xhtml</from-view-id>
            <navigation-case>
                <display-name>success</display-name>
                <from-outcome>success</from-outcome>
                <to-view-id>/index.xhtml</to-view-id>
            </navigation-case>
        </navigation-rule>
    </faces-config>