Versions Compared

Key

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

...

  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.
  2. Since "practice" is the name of the webapp which you are going to develop, create a hot-deploy/practice/webapp/practice folder. A component can consist of multiple webapps  . For example,the "marketing" component has two webapps "marketing" and "sfa".
  3. Create the hot-deploy/practice/webapp/practice/WEB-INF directory.
    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  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.
  4. 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/PracticeScreens.xml</param-value>
         <!-- change the path to the following if the above doesn't work for you -->
         <!-- <param-value>component://practice/webapp/practice/widget/PracticeScreens.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 . This will be explaned later in this tutorial only.
    2. For now put the value: "component://practice/widget/CommonScreens.xml" in for the mainDecoratorLocation and you . 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 This increases the code Independence from changing the path at changes in many places when we need to change the main decorator location. At that time we We will just need to change the location there only in one spot and it will work for all the screens where it has been used. One more Another 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 be used in multiple components where the same pattern is used at all the places and in all the components to show the mainDecoratorLocation. Concentrate on Remember this when you add decorators in your screens in not too distant future with the development of this application.

    3. 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>
             <!-- 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"/>
             <!-- change the path to the following if the above doesn't work for you -->
             <!-- <view-map name="main" type="screen" page="component://practice/webapp/practice/widget/PracticeScreens.xml#main"/> -->
      
             <!-- end of view mappings -->
      </site-conf>
      

      Creating the User Interface

  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.
  2. 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 the UI.
  3. 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 After this, you will be able to create screens views so an important reading at this place will be point is the Best Practices Guide.

    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>
    

...

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 webapp's 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 specified 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 :
  2. 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/request it 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.

...

  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 references at this moment are Understanding the OFBiz Widget Toolkit and "The Decorator" section in FAQ.
    Add a reference in web.xml to the CommonScreens.xml

    Code Block
    <context-param>
         <param-name>commonDecoratorLocation</param-name>
         <param-value>component://practice/webapp/practice/widget/CommonScreens.xml</param-value>
         <description>The location of the common-decorator screen to use for this webapp; referred to as a context variable in screen def XML files.</description>
    </context-param>
    
  2. Anchor
    include-menu
    include-menu
    Create a menu for this application . For this create by creating a file by name named PracticeMenus.xml in "widget" directory of you component. For this take a , reference from the 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="PracticeAppBar" 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 menu file in your CommonPracticeDecorator as follows:

    Code Block
    <screen name="CommonPracticeDecorator">
            <section>
                <widgets>
                    <include-menu location="component://practice/webapp/practice/widget/PracticeMenus.xml" name="PracticeAppBar"/>
                    <decorator-section-include name="body"/>
                </widgets>
            </section>
        </screen>
    
  3. 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 These scripts will be 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 . Create a file by name Person.groovy in this the "actions directory which will be fetching " directory to fetch all the records from the entity "Person". At this moment this is really going to be the small code for doing this very little code (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?

  4. 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 do 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>
    
  5. Now create a new screen by name entry named "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.commonDecoratorLocation}">
                        <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>
    
  6. 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 :

...

  1. Now add one more menu item to by name named "PersonForm" to your PracticeMenus.xml file.
  2. Create one file in widget by name named PracticeForms.xml and create a list form for showing the records from the 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>
    
  3. Create new screen by name named 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>
    
  4. Do the needful for showing Add this screen in to controller.xml.
    Now run the application again and observe the difference.
    Till Now So far you have worked on controller requests mappings, Screen widget, form widget, Decorator, Menus, groovy , and ftl.

Create main Decorator for decorating this application

  1. Create screen by name named "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>
    
  2. Now include this decorator in CommonPracticeDecorator screen which you are already having (see above Part 2 - Point 1: "Doing Some Advancements To User Interface")
    Now run it again and see the difference.

...