Open Source Strategies
 
Main
About
Learn More
Services
Projects
Jobs
Contact

SourceForge.net Logo

OFBiz Hello World Application Example

by Si Chen

IMPORTANT: Please read about the recent changes before attempting this tutorial.

This tutorial will show you how to build a very simple OFBiz application. You will see how OFBiz application components and web applications are created, how web pages are created, and how an OFBiz controller helps direct web requests.

This tutorial was done on Linux, but OFBiz and these examples will work with any operating system with a Java SDK.

Creating an Application

In OFBiz, every application sits inside its own fully contained component, so your first step is to create a component. A component can sit inside the framework/, application/, specialized/, or hot-deploy/ directory. The advantage of the hot-deploy/ directory is that components here are loaded automatically when OFBiz starts. So, for our first step, let's create a sub-directory in hot-deploy/ for our new component, which we'll call hello1:

sichen@linux:~/eclipse/workspace/ofbiz> ls -l hot-deploy/
total 4
drwxrwxr-x  4 sichen users 136 2005-05-19 07:16 hello1
-rw-r--r--  1 sichen users 127 2005-06-02 15:19 README.txt

(Note that everything in this tutorial is inside my eclipse/workspace/ directories because I use the Eclipse IDE, but in fact you can put ofbiz anywhere, and the directory structure is the same.)

Inside your new application component, there must be an ofbiz-component.xml file to tell OFBiz about your applicaton component: its data model (tables), business logic (services) and workflow, UI layer (web or GUI applications), any seed data it may have, and what other resources it requires. You can take a look at the ofbiz-component.xml files in other applications, which can be quite complex. For hello1, we just need to create a simple one that looks like this:

<?xml version="1.0" encoding="UTF-8"?>

<ofbiz-component name="hello1"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/ofbiz-component.xsd">
    <resource-loader name="main" type="component"/>
    <webapp name="hello1" 
    	    title="My First OFBiz Application" 
    	    server="default-server" 
    	    location="webapp/hello1" 
    	    mount-point="/hello1"
    	    app-bar-display="false"/>     
</ofbiz-component>
What is this file telling OFBiz?
  • That we have a component named "hello1"
  • That it should use the "main" resource-loader
  • That it has one web application, also called "hello1"
  • The "hello1" web application should use the "default-server" web server
  • The "hello1" web application is inside the webapp/ directory
  • The "hello1" web application should be mounted at a URI of "/hello1"
  • We don't want the app-bar, which shows all the applications available in OFBiz, to be displayed in our web app

Creating a Web Application

A web application is a UI component that interacts with the user over the web. An OFBiz application component can have several UI components, some of which are webapps.

Now that you have configured your new application, the next step is to create a webapp/ directory for its web applications. Inside this directory, create a hello1/ directory for the "hello1" web app you just named. When you are done, it should look like this:
sichen@linux:~/eclipse/workspace/ofbiz/hot-deploy/hello1> ls -l
total 4
-rw-------  1 sichen users 1733 2005-06-02 15:57 ofbiz-component.xml
drwxrwxr-x  3 sichen users   72 2005-06-02 15:54 webapp
sichen@linux:~/eclipse/workspace/ofbiz/hot-deploy/hello1> ls -l webapp/
total 0
drwxrwxr-x  3 sichen users 96 2005-06-02 16:10 hello1

Now we are ready to work inside the webapp/hello1 directory and create a web application. Remember that OFBiz is a Model-View-Controller framework, which means that a controller manages visitor requests and routes them to the appropriate pages and actions. Thus, separate pages and a master controller are needed.

Typically for Java web applications, pages which are viewable by visitors, such as HTML or JSPs, are inside a webapp/ directory, while private files, such as XML configuration files or Java servlets, are hidden inside a WEB-INF/ directory.

This is the case with OFBiz as well. We'll first create a WEB-INF/ directory and then create just one file to be displayed to our visitors, which we'll call main.ftl, for Freemarker template file. (Freemarker is a very easy, intuitive templating language that allows you to put basic controls, such as loops and if-then-else, around your HTML.) main.ftl is just a straightforward HTML file:

<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>HELLO</h1>
<p>Hello world!</p>
</body>
</html>
Now this would be your contents of your webapp/hello1/ directory:
sichen@linux:~/eclipse/workspace/ofbiz/hot-deploy/hello1/webapp/hello1> ls -l
total 4
-rw-------  1 sichen users 107 2005-06-02 16:23 main.ftl
drwxrwxr-x  2 sichen users 104 2005-06-02 16:17 WEB-INF

The final step is to create the files to configure the webapp. At a minimum, an OFBiz web application requires two configuration files, a controller.xml and a web.xml. controller.xml tells OFBiz what to do with various requests from visitors: what actions to take and what pages to render. web.xml tells OFBiz what resources (database and business logic access) are available for this web application and how to handle web-related issues, such as welcome pages, redirects, and error pages.

If you're starting a new application, both files can be copied from the WEB-INF/ directory of an existing application. I copied mine over from the catalog manager. web.xml can almost be used in place, with no modification, like this:

<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <display-name>Hello 1</display-name>
    <description>The First Hello World Application</description>

    <context-param>
        <param-name>entityDelegatorName</param-name>
        <param-value>default</param-value>
        <description>The Name of the Entity Delegator to use, defined in entityengine.xml</description>
    </context-param>
    <context-param>
        <param-name>localDispatcherName</param-name>
        <param-value>hello1</param-value>
        <description>A unique name used to identify/recognize the local dispatcher for the Service Engine</description>
    </context-param>
    <context-param>
        <param-name>serviceReaderUrls</param-name>
        <param-value>/WEB-INF/services.xml</param-value>
        <description>Configuration File(s) For The Service Dispatcher</description>
    </context-param> 

    <filter>
        <filter-name>ContextFilter</filter-name>
        <display-name>ContextFilter</display-name>
        <filter-class>org.ofbiz.webapp.control.ContextFilter</filter-class>
        <init-param>
            <param-name>disableContextSecurity</param-name>
            <param-value>N</param-value>
        </init-param>
        <init-param>
            <param-name>allowedPaths</param-name>
            <param-value>/control:/select:/index.html:/index.jsp:/default.html:
                               /default.jsp:/images:/includes/maincss.css</param-value>
        </init-param>
        <init-param>
            <param-name>errorCode</param-name>
            <param-value>403</param-value>
        </init-param>
        <init-param>
            <param-name>redirectPath</param-name>
            <param-value>/control/main</param-value>
        </init-param>        
    </filter>
    <filter-mapping>
        <filter-name>ContextFilter</filter-name>
            <url-pattern>/*</url-pattern>
    </filter-mapping> 

    <listener><listener-class>
              org.ofbiz.webapp.control.ControlEventListener</listener-class></listener>
    <listener><listener-class>
              org.ofbiz.webapp.control.LoginEventListener</listener-class></listener>
    <!-- NOTE: not all app servers support mounting implementations of the HttpSessionActivationListener interface -->
    <!-- <listener><listener-class>
          org.ofbiz.webapp.control.ControlActivationEventListener</listener-class></listener> -->
  
    <servlet>
        <servlet-name>ControlServlet</servlet-name>
        <display-name>ControlServlet</display-name>
        <description>Main Control Servlet</description>
        <servlet-class>org.ofbiz.webapp.control.ControlServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>ControlServlet</servlet-name>
        <url-pattern>/control/*</url-pattern>
    </servlet-mapping>

    <session-config>
        <session-timeout>60</session-timeout> <!-- in minutes -->
    </session-config>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
    </welcome-file-list>
</web-app>

The controller.xml can also be copied but needs to be modified to reflect your needs: what your URI requests you want to allow in your webapp, and how you want OFBiz to process them. Here is the controller modified for hello1:

<?xml version="1.0" encoding="UTF-8" ?>

<site-conf xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/site-conf.xsd">
    <description>First Hello World Site Configuration File</description>
    <owner>Open For Business Project (c) 2005 </owner>
    <errorpage>/error/error.jsp</errorpage>

    <handler name="java" type="request" class="org.ofbiz.webapp.event.JavaEventHandler"/>
    <handler name="soap" type="request" class="org.ofbiz.webapp.event.SOAPEventHandler"/>
    <handler name="service" type="request" class="org.ofbiz.webapp.event.ServiceEventHandler"/>
    <handler name="service-multi" type="request" class="org.ofbiz.webapp.event.ServiceMultiEventHandler"/>
    <handler name="simple" type="request" class="org.ofbiz.webapp.event.SimpleEventHandler"/>

    <handler name="ftl" type="view" class="org.ofbiz.webapp.ftl.FreeMarkerViewHandler"/>
    <handler name="jsp" type="view" class="org.ofbiz.webapp.view.JspViewHandler"/>
    <handler name="screen" type="view" class="org.ofbiz.widget.screen.ScreenWidgetViewHandler"/>

    <handler name="http" type="view" class="org.ofbiz.webapp.view.HttpViewHandler"/>

    <preprocessor>
        <!-- Events to run on every request before security (chains exempt) -->
        <!-- <event type="java" path="org.ofbiz.webapp.event.TestEvent" invoke="test"/> -->
        <event type="java" path="org.ofbiz.securityext.login.LoginEvents" invoke="checkExternalLoginKey"/>
    </preprocessor>
    <postprocessor>
        <!-- Events to run on every request after all other processing (chains exempt) -->
        <!-- <event type="java" path="org.ofbiz.webapp.event.TestEvent" invoke="test"/> -->
    </postprocessor>

    <!-- Request Mappings -->
    <request-map uri="main">
        <response name="success" type="view" value="main"/>
    </request-map>

    <!-- end of request mappings -->

    <!-- View Mappings -->
    <view-map name="error" page="/error/error.jsp"/>
    <view-map name="main" type="ftl" page="main.ftl"/>
    <!-- end of view mappings -->
</site-conf>
The OFBiz controller allows you to specify:
  • handlers, which are Java classes that handle either requests or produce views in various formats. For example, the handler for "java" events routes requests to a Java servlet, while the "service" handler routes requests to the service engine, automatically parsing visitor input into service input parameters. The various view requests produce output to the browser based on Freemarker templates, velocity, JSP, or the OFBiz screen widget.
  • pre- and post-processors, which are servlets that are run before and after every web request.
  • request mappings, which map URI requests to either request or view handlers. Request mappings can also re-direct to other request mappings, allowing requests to be chained together.
  • view mappings, which generate output to the visitor by specifying where the page is located. By default, view mappings reference files starting from the current web application's directory, in this case, webapp/hello1/.

In this simple controller, there are no pre- or postprocessor events to be run. Only one request is allowed, "/main", and it leads us to a view called "main", which uses main.ftl we created earlier to generate output back to the visitor.

Running our application

Now we are ready. Let's run our first application:

sichen@linux:~/eclipse/workspace/ofbiz> ./startofbiz.sh 
sichen@linux:~/eclipse/workspace/ofbiz> tail -f logs/console.log 
In Linux, the startup script runs OFBiz in the background, so you need tail to see the console output. In Windows, just do:
c:\ofbiz> startofbiz.bat
and the output is displayed on your screen. The log file is quite lengthy but you will see these lines:
...
1607  (main) [ ComponentContainer.java:153:INFO ] Auto-Loading component directory : [/home/sichen/eclipse/workspace/ofbiz/hot-deploy]
1619  (main) [            UtilXml.java:242:DEBUG] XML Read 0.011s: file:/home/sichen/eclipse/workspace/ofbiz/hot-deploy/hello1/ofbiz-component.xml
1620  (main) [ ComponentContainer.java:209:INFO ] Loading component : [hello1]
...
18571 (main) [      ContextFilter.java:300:INFO ] [ContextFilter.init] Getting Entity Engine Delegator with delegator name default
18573 (main) [  ServiceDispatcher.java:168:INFO ] Registered dispatcher: hello1
18575 (main) [  GenericDispatcher.java:85 :INFO ] [LocalDispatcher] : Created Dispatcher for: hello1
18577 (main) [     ControlServlet.java:74 :INFO ] [ControlServlet.init] Loading Control Servlet mounted on path /home/sichen/eclipse/workspace/ofbiz/hot-deploy/hello1/webapp/hello1/
18578 (main) [     RequestHandler.java:89 :INFO ] [RequestHandler Loading...]
18587 (main) [            UtilXml.java:242:DEBUG] XML Read 0.0080s: jndi:/0.0.0.0/hello1/WEB-INF/controller.xml
18588 (main) [    ConfigXMLReader.java:552:INFO ] ConfigMap Created: (4) records in 0.0010s
18588 (main) [    ConfigXMLReader.java:622:INFO ] HandlerMap Created: (2) records in 0.0s
18589 (main) [    ConfigXMLReader.java:302:INFO ] RequestMap Created: (1) records in 0.0s
18589 (main) [    ConfigXMLReader.java:411:INFO ] ViewMap Created: (2) records in 0.0s
...
21204 (main) [  CatalinaContainer.java:238:INFO ] Connector AJP/1.3 @ 8009 - not-secure [org.apache.jk.server.JkCoyoteHandler] started.
21204 (main) [  CatalinaContainer.java:235:INFO ] Connector HTTP/1.1 @ 8080 - not-secure [org.apache.coyote.http11.Http11Protocol] started.
21205 (main) [  CatalinaContainer.java:235:INFO ] Connector TLS @ 8443 - secure [org.apache.coyote.http11.Http11Protocol] started.
21209 (main) [  CatalinaContainer.java:242:INFO ] Started Apache Tomcat/5.5.9
Httpd started on port: 9989
Sessiond started on port: 9990
21467 (main) [ BeanShellContainer.java:109:INFO ] Started BeanShell telnet service on 9989, 9990
21467 (main) [ BeanShellContainer.java:110:INFO ] NOTICE: BeanShell service ports are not secure. Please protect the ports
31903 (org.ofbiz.service.jms.JmsListenerFactory@996b65) [ JmsListenerFactory.java:82 :INFO ] JMS Listener Factory Thread Finished; All listeners connected.
The first little block shows OFBiz auto-loading the hello1 component from within hot-deploy/. The second block shows it setting up the hello1 webapp, getting a delegator (for database access), a dispatcher (for running services), and loading up the controller. The last block is what you will see when all the webapps are loaded and Tomcat, the default embedded web server, is started.

From a browser, type in:

http://localhost:8080/hello1/control/main
and you will see this.

Final Touchups

Looks like we're done... but not yet. Try typing this in your browser:

http://localhost:8080/hello1/
and you will get this. The problem is that /control is a specific request to the control servlet through the web server, and there is no index page at the root of the webapp. This is simple to fix: just copy an index.jsp from one of the other webapps into /webapp/hello1/. The index.jsp just has one line:
sichen@linux:~/eclipse/workspace/ofbiz/hot-deploy/hello1/webapp/hello1> cat index.jsp 

<%response.sendRedirect("control/main");%>
Now if you try it again, http://localhost:8080/hello1/ will also get you to the right page.

One last thing to try, type in:

http://localhost:8080/hello1/control/nonsense
You'd get a blank screen, because there is no error page right now. The location of your error page is specified in the beginning of your controller.xml above. You will need to make or copy over a /webapp/hello1/error/error.jsp page to show an error message to your visitors. It looks like this:
sichen@linux:~/eclipse/workspace/ofbiz/hot-deploy/hello1/webapp/hello1> cat error/error.jsp 

<%@ page import="org.ofbiz.base.util.*" %>
<html>
<head>
<title>Open For Business Message</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>

<% String errorMsg = (String) request.getAttribute("_ERROR_MESSAGE_"); %>

<body bgcolor="#FFFFFF">
<div align="center">
  <br/>
  <table width="100%" border="1" height="200">
    <tr>
      <td>
        <table width="100%" border="0" height="200">
          <tr bgcolor="#CC6666"> 
            <td height="45"> 
              <div align="center"><font face="Verdana, Arial, Helvetica, sans-serif" size="4" color="#FFFFFF"><b>:ERROR MESSAGE:</b></font></div>
            </td>
          </tr>
          <tr> 
            <td>
              <div align="left"><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><%=UtilFormatOut.replaceString(errorMsg, "\n", "<br/>")%></font></div>
            </td>
          </tr>
        </table>
      </td>
    </tr>
  </table>
</div>
<div align="center"></div>
</body>
</html>
/html>
Now try the "nonsense" request again, and you should get this page. Note that this is a very different error page: it is not from Apache Tomcat, like the first one you got, but from OFBiz. This is because with "/control" in your URI (and the re-direct even if you didn't have it), every request is being processed by the OFBiz controller now.

This is the final content of your webapp directory:

sichen@linux:~/eclipse/workspace/ofbiz/hot-deploy/hello1/webapp/hello1> ls -l
total 8
drwxr-xr-x  2 sichen users  144 2005-06-03 06:01 error
-rw-r--r--  1 sichen users   44 2005-06-03 05:52 index.jsp
-rw-------  1 sichen users 1355 2005-06-02 16:26 main.ftl
drwxrwxr-x  2 sichen users  232 2005-06-03 05:58 WEB-INF
sichen@linux:~/eclipse/workspace/ofbiz/hot-deploy/hello1/webapp/hello1> ls -l error/
total 4
-rw-r--r--  1 sichen users 1003 2005-06-03 05:55 error.jsp

Click to see the complete files for this application.

Conclusions

So now you have created a fully self-contained ofbiz application, with its webapp, controller, page, and error page. This sure was a lot of work to display a simple web page. Obviously, if that's all you needed, OFBiz is way too complicated. But chances are, that's never all you needed to do. In future tutorials, we'll see how you can use OFBiz applications to develop your complex applications with a lot of different tables, pages, and complicated business logic. Then you will see the advantages of the OFBiz framework.


© 2005-2007 Open Source Strategies, Inc. All rights reserved.