Versions Compared

Key

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

...

  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.
  2. 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>
    
  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 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?
  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 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 "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>
    
  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 :

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.
  2. 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>
    
  3. 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>
    
  4. 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.

...

  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>
    
  2. 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.

...

  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.
  2. 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>
    
  3. 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.
  4. 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:

...

Secure Your Application by Authentication

  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"/>
    
  2. 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
    2. Once your logged in search for the user by typing 'admin' in the User Login field and then clicking the Lookup Party button.
    3.    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 partyId admin has multiple login Ids as listed in the
      User Name(s) form.
    4. 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.
    5. 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'
    6. 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

Create, Update and Delete operations for an entity will be done by services which we will be writing in minilang.
At first approach we will write our own services for performing these operations for making a better understanding with it.
Onwards we will be doing this by calling already implemented services.
For doing so we will take the entities from Party model which are:
--Party
--Person
A person is a party so for the creation of a person first a party needs to be created with partyTypeId="PERSON".
So there can be two ways to do that:
1. Create service for the creation of a party with type Person.
2. Create a party first in the service which will be creating person.

...

Writing Services

Step - 1: Create directory by name "servicedef" in component directory "practice". This directory will contain all the service definition files e.g. services.xml, secas.xml.
Note If it is a service which is written in Java then it will be placed in "src" directory and if it is a service which is written in minilang then it will be placed in script directory. e.g. for java applications/party/src/org/ofbiz/party/party/PartyServices.java and for minilang applications/party/script/org/ofbiz/party/party/PartyInvitationServices.xml. Respective class path and file path will be mentioned in the service definition.
*Step - 2 :*In controller you have to create an entry for the request for the execution of a service and set the response like

...

So whenever you make any change in any service definition then you must restart the server to have changes in effect.

Writing CRUD Operations for Party Entity

First we will be writing services for Party then while writing services for creating Person we will be calling the service for party.
Step - 1 :Create a file by name "services.xml" in servicedef directory.
Step - 2 : Define services for CRUD operations for Party entity. Name of services will be createPracticeParty, updatePracticeParty, deletePracticeParty and specify the correct location to the file where these services will be implemented like /framework/example/script/org/ofbiz/example/example/ExampleServices.xml.
Step - 3 : Create directory structure and PracticeServices.xml file in your component directory for giving the implementation of these services.
(For implementation take reference from services.xml and ExampleServices.xml files of Example component)
Note : Do not use the <override> tag as it is introduced later in the tutorial. 
From this place if you want to run these services then you can run them by webtools--> Run Service . By this place you can test your services.
Note: At this place you must read http://markmail.org/message/dj4wvtm4u2nxoz3r. This feature has been recently added against the traditional approach of writing CRUD operations for an entity.
This new feature enables you to just define the services by mentioning the operation you want to perform.Basically just set the engine attribute to "entity-auto" and the invoke attribute to "create", "update", or "delete".
like you can take a look in the following code from services.xml of example component:  

...

engine="entity-auto" invoke="create" play the role for creating the records for the default-entity "Example."
Here for practice you may go by following further steps those steps will help you in understanding the concept then onwards you can practice the pattern given above  in your code as its the best practice for these kind of simple operations in OFBiz.

Writing CRUD Operations for Person Entity

- Here for the creation of record for person entity we will need to have the partyId for that so we will first call the service createPracticeParty then after getting the partyId we will create the record for person.
- Here we will be adding one add form in the bottom of the list form which we have for the person entity. This form will be calling the services for creating a record for person.
Step - 1 : Create the add form for the creation of person and add this in the same screen for person form.

...

Step - 4 :  Create controller entries for these services which are going to be called by this form.
Now run the application and see the output screen as bellow:
Output Screen:

Writing Events

Events can be written in Java and minilang both. Now the next development which you are going to do will be writting these events.
Events are used for the validation and conversion using Simple Map Processor. The Simple Map Processor Mini-Language performs two primary tasks: validation and conversion. It does this in a context of moving values from one Map to another. The input map will commonly contain Strings, but can contain other object types like Integer, Long, Float, Double, java.sql.Date, Time, and Timestamp.
Before moving any further an important link to go through is : http://docs.ofbiz.org/display/OFBIZ/Mini-Language+Guide#Mini-LanguageGuide-smapFor making an understanding with it implementation will be done by performing following steps:
Step - 1 : For this create another tab in your practice application menu bar for this by Name "Events".
Step - 2 : Now create another menu with two menu item in PracticeMenus.xml file by name "EventMenu". This menu will be having 2 menu Item one will be by name "EventMinilang" and  another by name "EventJava". One will be used to show the form which we will be calling an event which will be in minilang and other will be used to call java event.
Step - 3 : Simply show form on the request of both which will be for creating a new person. Both the forms will be different for calling different events as target in them.

...