Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Sponsored by HotWax Media
Written by : Pranay Pandey with feedback and contributions from Chirag Manocha, Ravindra Mandre, Rob Schapper
Special thanks to Anil Patel and Mridul Pathak for inspiring me to write this tutorial.
Introduction to Ajax ajax in OFBiz added by Divesh Dutta and Arun Patidar, Special thanks to Rishi Solanki for the idea of introducing this section.

This tutorial document is meant for OFBiz beginners. It will help learn fundamentals of OFBiz application development process. Aim behind the creation of this tutorial is to acquaint a developer with best practices, coding conventions and the control flow and many more. This practice acts as the "Helloworld" for OFBiz similar as the first Helloworld when the programming "C" language was introduced by Kernighan and Richie.

...

Info
titleSource Code!

OFBiz
Download Apache OFBiz™
OFBiz Source Repository and Access

Tutorial
If you want take a quick reference of this tutorial, source code for Practice Application demonstrated in here can be downloaded from here: Download Source Code

Framework Introduction Videos
These are old but still worth watching if you want. You can watch OFBiz videos, which are available at Framework Introduction Videos, in parallel with the development of this application.

Table of Contents

Creating Practice Application (Hello World...)

...

  1. The ofbiz-component.xml file is responsible for letting OFBiz know where resources are at as well as allowing you to add to the classpath.
  2. # The 'resource-loader name' can be any string. Here we are setting it as "main". The 'type' tells OFBiz that we will be loading a component.
    Code Block
    <resource-loader name="main" type="component"/>
    
    3.
  3. In <webapp> tag, we have different attributes and their purpose is as follows:
    Code Block
    <webapp name="practice"
           title="Practice"
           server="default-server"
           base-permission="OFBTOOLS"
           location="webapp/practice"
           mount-point="/practice"
           app-bar-display="false"/>
    
    1. name :- defines the name of our web application.
    2. title :- This will be the title of the application which will be shown in the top navigation.
    3. server :- This will let OFBiz know what server to use.
    4. base-permission :- This line requires that the user should have the OFBTOOLS permission to be able to use the application. Since the 'admin' user has this permission we do not have to create any new users.
    5. location :- This will be the location that is the default base directory for the server.
    6. mount-point :- This is the URL used to access this resource. in this case it would be localhost:8080/practice.
    7. app-bar-display :- This will let OFBiz know if we want our component to show up in the main application tabs that are part of the common ofbiz decorator.

Creating the web app

...

  1. Create a "webapp" directory in the practice component (hot-deploy/practice/webapp).
    This directory contains all the webapp related files for the component we are creating.

...

  1. Create a sub-directory inside the webapp directory by the name of  "practice" which is the name of the webapp which you are going to develop (hot-deploy/practice/webapp/practice). A component can have multiple webapps attached to it. e.g. In the "marketing" component there are two webapps "marketing" and "sfa".
    The webapp we are creating will follow the J2EE webapp standards.

...

  1. Create WEB-INF directory in your webapp (hot-deploy/practice/webapp/practice/WEB-INF).
    An OFBiz web application requires two configuration files, a controller.xml and a web.xml. The 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.

...

  1. Create a file named "web.xml"(web.xml follows j2ee webapp specs). Contents of this file can be copied from any of the existing component e.g. /framework/example component. The Important values to change are the <display-name>, the localDispatcherName, the mainDecoratorLocation and the webSiteId.
    Code Block
    
    <context-param>
        <param-name>webSiteId</param-name>
        <param-value>PRACTICE</param-value>
        <description>A unique ID used to look up the WebSite entity to get information about catalogs, etc.</description>
    </context-param>
    <context-param>
         <param-name>localDispatcherName</param-name>
         <param-value>practice</param-value>
         <description>A unique name used to identify/recognize the local dispatcher for the Service Engine</description>
    </context-param>
    <context-param>
         <param-name>mainDecoratorLocation</param-name>
         <param-value>component://practice/widget/CommonScreens.xml</param-value>
         <description>The location of the main-decorator screen to use for this webapp; referred to as a context variable in screen def XML files.</description>
    </context-param> 
    
    1. For now just put websiteId as "PRACTICE", you will explanation after some time in this tutorial only.
    2. For now put the value: "component://practice/widget/CommonScreens.xml" in for the mainDecoratorLocation and you will see why in a while. This location is used in pointing to the main decorator location in screens like
      Code Block
      
      ${parameters.mainDecoratorLocation}
      
      Which increases the code Independence from changing the path at many places when we need to change the main decorator location. At that time we just need to change the location there only and it will work for all the screens where it has been used. One more advantage of doing this in screens is the purpose of resuability of existing screens which we can use from other components, but it decorate that screen by your decorator only as the same pattern is used at all the places and in all the components to show the mainDecoratorLocation. Concentrate on this when you add decorators in your screens in not too distant future with the development of this application.

...

  1. Create a file named "controller.xml" (used by ofbiz webapp controller)  This file will be small and simple at first but will grow as we add functionality later on. For now insert the following code:
    Code Block
    
    <?xml version="1.0" encoding="UTF-8"?>
    <site-conf xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/site-conf.xsd">
           <include location="component://common/webcommon/WEB-INF/common-controller.xml"/>
           <description>Practice Component Site Configuration File</description>
           <owner>Copyright 2001-2009 The Apache Software Foundation</owner>
           <handler name="screen" type="view" class="org.ofbiz.widget.screen.ScreenWidgetViewHandler"/>
           <!-- Request Mappings -->
           <request-map uri="main">
               <security https="false" auth="false"/>
               <response name="success" type="view" value="main"/>
           </request-map>
           <!-- end of request mappings -->
           <!-- View Mappings -->
           <view-map name="main" type="screen" page="component://practice/widget/PracticeScreens.xml#main"/>
           <!-- end of view mappings -->
    </site-conf>
    

...

  1. Move up one level and create a new directory named 'error'(hot-deploy/practice/webapp/practice/error).

      ...

        1. Create a file error.jsp inside the "error" directory. Contents of this file can be copied from any of the existing component e.g. example component.
          The location of your error page will be specified in the beginning of your controller.xml file like <errorpage>/error/error.jsp</errorpage> . You will need to make or copy over a /webapp/practice/error/error.jsp page to show an error message to the user.

      ...

      1. Create a sub-directory inside your component directory "practice" named "widget"(hot-deploy/practice/widget). This directory will contain your forms, menus, and screens which will be created for UI.

      ...

      1. Create a file inside the directory "widget" named "PracticeScreens.xml". Contents of this file can be copied from any existing component  e.g. example component.
        As now onwards you will be able to create screens views so an important reading at this place will be Best Practices Guide

      ...

      1. .

        ...

        Code Block
        
        <?xml version="1.0" encoding="UTF-8"?>
        <screens xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/widget-screen.xsd">
            <screen name="main">
                <section>
                    <widgets>
                        <label text="This is first practice"/>
                    </widgets>
                </section>
            </screen>
        </screens>
        

      ...

      1. Now that we have the basic elements in place let's review the basic flow no matter how large or complex your component gets. First, a request will be made by a browser to see a specific resource. Take for example the request: "localhost:8080/practice/control/main"
        1. When OFBiz sees this request it will look at the /practice section first. This is because in our ofbiz-component.xml file we said our webapps mount point would be /practice. Now OFBiz knows that our practice component will handle the rest of the request.
        2. OFBiz will then look at our controller.xml file. Inside our controller.xml file we have request-maps and view-maps. If it finds a request-map with the name 'main' it will use the associated view-map, as follows. The request-map can either specify a view, or as we will see later an event or a service. If it specifies a view it will look further down in the controller.xml file and see if there is a view-map with the name specified by the value tag in the request-map.
        3. For now we will keep it simple and assume that all the views go to a type=screen. If this is the case then the page tag will specify a path to a screen definition file as well as a screen name to display after the "#" sign.

      ...

      1. Now its the time to run you first practice application!
        Start the server by typing the following at the command line : java -Xmx256M -jar ofbiz.jar (the -Xmx256M command just ensures that the program has enough memory) Then, hit the url http://localhost:8080/practice/control/main in your browser.  Your browser should show "This is first practice" as seen below.
        Output Screen :
        Image Modified

      ...

      1. Create a file in the webapp directory "practice" named index.jsp (Contents of this file can be copied from the "example" component). This file is responsible for redirecting the response to control/main if you give a url such as  http://localhost:8080/practice/. If you give a url such as http://localhost:8080/practice/unknown/requestit will be redirected to the redirectPath specified in web.xml. In that case, ContextFilter will filter out the request and use the redirect path to redirect the request.

      Part 2

      Doing Some Advancements To User Interface

      ...

      1. Now it is time to create a decorator for the screens in this application. Create a file named CommonScreens.xml in the "widget" directory. This file will contain the common screens which will be used throughout the entire application. A common screen may have a header and footer included so any other screens that use it as a decorator will also have those items. For this you can take reference from the CommonScreens.xml file in the "example" component.
        CommonScreens.xml file code will be:
        Code Block
        
         <screen name="CommonPracticeDecorator">
              <section>
                  <widgets>
                       <decorator-section-include name="body"/>                     
                  </widgets>
              </section>
        </screen>
        
        Refer to the "CommonScreens.xml" file in the "Example" component to see usage of main-decorator.  Two important readings at this moment are Understanding the OFBiz Widget Toolkit and "The Decorator" section in FAQ.

      ...

      1. Create a menu for this application. For this create a file by name PracticeMenus.xml in "widget" directory of you component. For this take a reference from ExampleMenus.xml file of "example" component.
        Code Block
        
        <?xml version="1.0" encoding="UTF-8"?>
        <menus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/widget-menu.xsd">
            <menu name="MainAppBar" title="PracticeApplication" extends="CommonAppBarMenu" extends-resource="component://common/widget/CommonMenus.xml">
                <menu-item name="main" title="Main"><link target="main"/></menu-item>
            </menu>
        </menus>
        
        Include this menus file in your CommonPracticeDecorator as follows:
        Code Block
        
        <screen name="CommonPracticeDecorator">
                <section>
                    <widgets>
                        <include-menu location="component://practice/widget/PracticeMenus.xml" name="MainAppBar"/>
                        <decorator-section-include name="body"/>
                    </widgets>
                </section>
            </screen>
        

      ...

      1. Create the sub-directory "actions" inside the WEB-INF directory.
        In this directory we will create the scripting files. Scripting files are used to prepare data on fly. These files will be groovy files. Earlier we were using bsh(beanshell) files. This is a script which is used to fetch the data from database on the fly for the UI.
        Reference : Tips & Tricks while working with Groovy & http://groovy.codehaus.org/. While working in groovy always be conscious about the imported classes and packages. Import only those which have been used in your file. For putting log messages use methods from "Debug" class just do this practice from the beginning itself. So create a file by name Person.groovy in this actions directory which will be fetching all the records from the entity "Person". At this moment this is really going to be the small code for doing this (a single line) like
        Code Block
        
        context.persons = delegator.findList("Person", null, null, null, null, false);
        
        The above statement will fetch all the records from the Person entity and will put them in context by the name persons. Now this list by the name person will be iterated in the ftl file to show the records.
        At this place an important reading is available at : Which variables are available in screen context?

      ...

      1. Now in webapp "practice" create one ftl file by name "Person.ftl" which will be used to show the data fetched by groovy file.
        Reference : http://freemarker.sourceforge.net/docs/
        At this moment you need only to iterate the list of persons which is there in the context. The only code that is needed to that is:
        Code Block
        
        <#if persons?has_content>
          <h2>Some of the people who visited our site are:</h2>
          <br>
          <ul>
            <#list persons as person>
              <li>${person.firstName?if_exists} ${person.lastName?if_exists}</li>
            </#list>
          </ul>
        </#if>
        

      ...

      1. Now create a new screen by name "person" in PracticeScreens.xml file and also create a new menu item in PracticeMenus.xml file.
        PracticeScreens.xml new screen entry will be:
        Code Block
        
            <screen name="person">
                <section>
                    <actions>
                        <script location="component://practice/webapp/practice/WEB-INF/actions/Person.groovy"/>
                    </actions>
                    <widgets>
                        <decorator-screen name="CommonPracticeDecorator" location="${parameters.mainDecoratorLocation}">
                            <decorator-section name="body">
                                <platform-specific>
                                    <html>
                                        <html-template location="component://practice/webapp/practice/Person.ftl"/>
                                    </html>
                                </platform-specific>
                            </decorator-section>
                        </decorator-screen>       
                    </widgets>
                </section>
            </screen>
        

      ...

      1. Now change the controller.xml file so it points to the new screen, as we did earlier.
        Now again run the application and observe the results by giving http://localhost:8080/practice/control/person .
        Tip
        titleHint

        If the output screen does not contain the menu as shown below, you will most likely need to change auth="true" to auth="false" in your controller.xml for the menu to come up.

        Output Screen :
        Image Modified

      Now moving to create a form for showing the content of Person entity on the screen (Using Form Widget)

      ...

      1. Now add one more menu item to by name "PersonForm" to your PracticeMenus.xml file.

      ...

      1. Create one file in widget by name PracticeForms.xml and create a list form for showing the records from person entity.
        (Take reference from ExampleScreens.xml and ExampleForms.xml files).
        Code Block
        
                <form name="ListPersons" type="list" list-name="persons" list-entry-name="person"  default-map-name="person" paginate-target="personForm">
                    <!-- Important: Here service definition for updatePracticePerson has been used for automatically rendering the form fields, which you can use after completing CRUD operations from Part-3 -->
                    <!-- auto-fields-service service-name="updatePracticePerson" default-field-type="display" map-name="person"/-->
        
                    <!-- The above method can be used in case a service specific form is being rendered, otherwise form-fields can be explicitly mentioned as given below:-->
                    <field name="firstName"><display/></field>
                    <field name="middleName" ><display/> </field>
                    <field name="lastName" ><display/> </field>
               </form>
        

      ...

      1. Create new screen by name personForm and include this list form in it.
        Code Block
        
        <screen name="PersonForm">
                <section>
                    <actions>
                        <set field="headerItem" value="personForm"/>
                        <set field="titleProperty" value="PageTitlePracticePersonForm"/>
                        <entity-condition entity-name="Person" list="persons"/>
                    </actions>
                    <widgets>
                        <decorator-screen name="CommonPracticeDecorator" location="${parameters.mainDecoratorLocation}">
                            <decorator-section name="body">
                                <label text="Person List" style="h2"/>
                                <include-form name="ListPersons" location="component://practice/widget/PracticeForms.xml"></include-form>
                            </decorator-section>
                        </decorator-screen>       
                    </widgets>
                </section>
        </screen>
        

      ...

      1. Do the needful for showing this screen in controller.xml.
        Now run the application again and observe the difference.
        Till Now you have worked on controller requests mappings, Screen widget, form widget, Decorator, Menus, groovy, ftl.

      Create main Decorator for decorating this application

      ...

      1. Create screen by name "main-decorator" in CommonScreens.xml file.(Take reference from CommonScreens.xml file of Example component.)
        Code Block
        
        <screen name="main-decorator">
                <section>
                    <actions>
                        <property-map resource="CommonUiLabels" map-name="uiLabelMap" global="true"/>
                        <property-map resource="PracticeUiLabels" map-name="uiLabelMap" global="true"/>
                        <set field="layoutSettings.companyName" from-field="uiLabelMap.PracticeCompanyName" global="true"/>
                        <set field="activeApp" value="practice" global="true"/>
                        <set field="applicationMenuName" value="PracticeAppBar" global="true"/>
                        <set field="applicationMenuLocation" value="component://practice/widget/PracticeMenus.xml" global="true"/>
                    </actions>
                    <widgets>
                        <include-screen name="GlobalDecorator" location="component://common/widget/CommonScreens.xml"/>
                    </widgets>
                </section>
        </screen>
        

      ...

      1. Now include this decorator in CommonPracticeDecorator screen which you are already having.
        Now run it again and see the difference.

      Now its the time to show practice application in the app bar

      ...

      • For this just make app-bar-display="true" in ofbiz-component.xml file.
        Restart the server then run it again you will find practice application in app bar.

      Create UI Labels

      ...

      1. For this create directory by name "config" in your component directory i.e. "practice".
        Note: -Here remember to create an entry for the config directory in your ofbiz-component.xml file.
        which will be:
        Code Block
        
        <classpath type="dir" location="config"/>
        
        That means you have to place the config directory on the classpath to access configuration files.

      ...

      1. Now create a file by name PracticeUiLabels.xml and create some of the ui labels for practice applicaton. (take reference from ExampleUiLabels.xml). Here remember one thing whenever you make a change in UiLabels then you have to restart the server for having the changes in effect. At first create only 2 ui labels like
        Code Block
        
        <property key="PracticeApplication">
            <value xml:lang="en">This is first 	practice</value>
        </property>
        <property key="PracticeCompanyName">
            <value xml:lang="en">OFBiz: Practice</value>
        </property>
        

      ...

      1. Include this UI Label resource in your main decorator screen which you created earlier and use these one or two ui labels which you are having now.

      ...

      1. Use those 2 UI labels at appropriate places.
        Note: Always search first for any existing Ui label in ofbiz and if you don't find it there then only create new one.
        Now run the application and see the output screen as bellow from :
        Output Screen:
        Image Modified

      Now its time to make this practice application secure by checking authentication (user login)

      ...

      1. Take reference from ExampleMenus.xml file for having login and logout options in your menu.
        Targets for these options will be available from "component://common/webcommon/WEB-INF/common-controller.xml", which we have to include in our controller.xml.
        or you can do these entries in your controller.xml file under
        Code Block
        
        <!- Request Mappings ->
        <!-- Security Mappings -->
         <request-map uri="checkLogin" edit="false">
            <description>Verify a user is logged in.</description>
                <security https="true" auth="false"/>
                <event type="java" path="org.ofbiz.webapp.control.LoginWorker" invoke="checkLogin" />
                <response name="success" type="view" value="main"/>
                <response name="error" type="view" value="login"/>
            </request-map>
            <request-map uri="login">
                <security https="true" auth="false"/>
                <event type="java" path="org.ofbiz.webapp.control.LoginWorker" invoke="login"/>
                <response name="success" type="view" value="main"/>
                <response name="error" type="view" value="login"/>
            </request-map>
            <request-map uri="logout">
                <security https="true" auth="true"/>
                <event type="java" path="org.ofbiz.webapp.control.LoginWorker" invoke="logout"/>
                <response name="success" type="request" value="checkLogin"/>
                <response name="error" type="view" value="main"/>
            </request-map>
        
        These requests are needed to add in your controller only when you have not included any of the other component controller which consist of these requests. So if you have already included common-controller.xml file then you don't need to explicitly do these entries in your controller.    
        and the same view we have in place can be used for which we have entry in common-controller.xml file we can also have our own:
        Code Block
        
        <view-map name="login" type="screen" page="component://common/widget/CommonScreens.xml#login"/>
        

      ...

      1. Make changes in requests in controller.xml file make auth="true" means now these requests needs authentication.
        This is first security level which you have implemented. you request should look like :
        Code Block
        
        <request-map uri="main">
            <security https="true" auth="true"/>
            <response name="success" type="view" value="main"/>
            <response name="error" type="view" value="main"/>
        </request-map>
        
        Now run your application and observe the difference. you can login by user name : admin and pwd: ofbizHere we should understand why we had given the permission "OFBTOOLS" in base-permission in ofbiz-component.xml file. To understand this please read following carefully and perform steps as mentioned:
        Confirm that user 'admin' has the 'OFBTOOLS' permission.

      ...

      1. Login into partymanager to confirm that the user admin has the required permission https://127.0.0.1:8443/partymgr/control/main

      ...

      1. Once your logged in search for the user by typing 'admin' in the User Login field and then clicking the Lookup Party button.

      ...

      1.    This does a wild char*  search and you should see multiple users returned.Click the 'Details' button for the admin user.
        Note : Important point to note here is that the person 'Mr. THE PRIVILEGED ADMINISTRATOR' has a

      ...

      1. partyId admin has multiple

      ...

      1. login Ids as listed in the
        User Name(s) form.

      ...

      1. We interested in the admin user login so click on the 'Security Groups' button and confirm that the use 'admin' is part of the 'FULLADMIN' group. The Groups that the user belongs to is shown in the bottom list form Drill down on the FULLADMIN.

      ...

      1. Click on the Permissions tab. This tab shows all the permissions for the FULLADMIN security group. Navigate between the permissions till you find the OFBTOOLS permissions.
        'OFBTOOLS_VIEW Permission to access the Stock OFBiz Manager Applications.' This confirms that the userlogin 'admin' has the permission 'OFBTOOLS'

      ...

      1. Take a moment  to review the entity model as it relates to users and permissions. The arrow represents the many side of the relationship.An really important reading at this moment is at : OFBiz Security

      Part 3

      Writing CRUD Operations

      ...