Versions Compared

Key

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

...

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 record, first a party record needs to be created with partyTypeId="PERSON".
So there can be two ways to do that:1.

  1. Create service for the creation of a party with party type

...

  1. "PERSON".

...

  1. Create a party first in the service which will be creating person.

Writing Services

...

  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.

...

  1. In controller you have to create an entry for the request for the execution of a service and set the response like.
    Code Block
    
    <request-map uri="createPracticePerson">
        <security https="true" auth="true"/>
        <event type="service" invoke="createPracticePerson"/>
        <response name="success" type="view" value="PersonForm"/>
    </request-map>
    

...

  1. Now all the services which you have written needs to be loaded when server starts so you need to do an entry for service definition in ofbiz-component.xml file which will be like:
    Code Block
    
    <service-resource type="model" loader="main" location="servicedef/services.xml"/>
    
    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 :

  1. Create a file by name "services.xml" in servicedef directory.

...

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

...

  1. Create directory structure and PracticeServices.xml file in your component directory for giving the implementation of these services.

...

  1. (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.

...


  1. 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:  
    Code Block
    
    <service name="createExample" default-entity-name="Example" engine="entity-auto" invoke="create" auth="true">
        <description>Create a Example</description>
        <permission-service service-name="exampleGenericPermission" main-action="CREATE"/>
        <auto-attributes include="pk" mode="OUT" optional="false"/>
        <auto-attributes include="nonpk" mode="IN" optional="true"/>
        <override name="exampleTypeId" optional="false"/>
        <override name="statusId" optional="false"/>
        <override name="exampleName" optional="false"/>
    </service>
    

    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.

    h4. Writing

...

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

...

  1. Create the add form for the creation of person and add this in the same screen for person form.
    Code Block
    
    <form name="CreatePerson" type="single" target="createPracticePerson">
          <auto-fields-service service-name="createPracticePerson"/>
          <field name="submitButton" title="Create" widget-style="smallSubmit"><submit button-type="button"/></field>
    </form>

...

...

  1. Write CrUD operations for person entity.this is a code for createPracticePerson in services.xml
    Code Block
    
    <service name="createPracticePerson" default-entity-name="Person" engine="simple"
              location="component://practice/script/org/hotwax/practice/PracticeServices.xml" invoke="createPracticePerson" auth="true">
         <description>Create a Person</description>
         <auto-attributes include="pk" mode="OUT" optional="false"/>
         <attribute name="salutation" mode="IN" type="String" optional="true"/>
         <attribute name="firstName" mode="IN" type="String" optional="false"/>
         <attribute name="middleName" mode="IN" type="String" optional="true"/>
         <attribute name="lastName" mode="IN" type="String" optional="false"/>
         <attribute name="suffix" mode="IN" type="String" optional="true"/>
    </service>  
    

    similar for Update and Delete 

...

  1. # Now convert the List form with editable field (Ref. ListExampleItems from ExampleForms.xml) and add Update and delete option with it and also in the same screen there is add form also. As shown bellow:
    Code Block
    
    <form name="ListPersons" type="list" list-name="persons" list-entry-name="person" target="updatePracticePerson" paginate-target="personForm">
            <auto-fields-service service-name="updatePracticePerson" default-field-type="edit" map-name="person"/>
            <field name="partyId"><hidden/></field>
            <field name="submitButton" title="Update" widget-style="smallSubmit"><submit button-type="button"/></field>
            <field name="deletePracticePerson" title="Delete Person" widget-style="buttontext">
            <hyperlink target="deletePracticePerson?partyId=${person.partyId}" description="Delete"/>
          </field>
    </form>
    

...


  1. # 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:
    Image Modified

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 :

  1. For this create another tab in your practice application menu bar for this by Name "Events".

...

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

...

  1. 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.
    Code Block
    
    <menu name="EventMenu" default-menu-item-name="eventMinilang" default-selected-style="selected"
             type="simple" menu-container-style="button-bar button-style-1" selected-menuitem-context-field-name="headerItem">
          <menu-item name="eventMinilang" title="Create Person --- Event MiniLang">
               <link target="createPracticePersonEventM"/>
          </menu-item>
          <menu-item name="eventJava" title="Create Person --- Event Java">
               <link target="createPracticePersonEventJ"/>
          </menu-item>   
    </menu>
    

...

  1. Show labels in screens above the form like "New Person - Simple Event"  and  "New Person - Java Event" so that it will be easy to identify the purpose of that form.

...

  1. Now set event in target of the forms and create request mappings in controller for the event.
    Here important thing to note is in case of simple event controller entry will be like :
    Code Block
    
    <request-map uri="createPracticePersonSimpleEvent">
        <security https="true" auth="true"/>
        <event type="simple" path="component://practice/script/org/hotwax/practice/PracticeEvents.xml" invoke="createPracticePersonSimpleEvent"/>
        <response name="success" type="view" value="CreatePracPersonSimpleEvent"/>
        <response name="error" type="view" value="CreatePracPersonSimpleEvent"/>
    </request-map>
    
    Here the path is the path of the file where the event is written. it will be practice/script/org/hotwax/practice.
    and for java event controller entry will be like:
    Code Block
    
    <request-map uri="createPracticePersonJavaEvent">
        <security https="true" auth="true"/>
        <event type="java" path="org.hotwax.practice.PracticeEvents" invoke="createPracticePersonJavaEvent"/>
        <response name="success" type="view" value="CreatePracPersonJavaEvent"/>
        <response name="error" type="view" value="CreatePracPersonJavaEvent"/>
    </request-map>
    
    Here the path is the classpath in which this event is defined. 
    The file name will be PracticeEvents.java and will be created at  practice/src/org/hotwax/practice.

Simple Minilang Event

...

  1. Now in the script/org/hotwax/practice/ create one file by name PracticeEvents.xml.

...

  1. Write the event in PracticeEvents.xml file by name createPracticePersonSimpleEvent.(For reference you can go through the event "createUser" from UserEvents.xml from party component)
    The event which you will be writing should be the simple one as you just have to process 5 fields coming from the form which are salutation, firstName, middleName, lastName, suffix. and then you have to call the createPracticePerson service.
    For processing the field you will be using simple map processor as you have read earlier. 
    Follow these steps for writing the event:

      ...

        1. Process fields coming from the form like: 
          Code Block
          
          <call-map-processor in-map-name="parameters" out-map-name="createPersonContext">
              <simple-map-processor name="createPersonMap">
                  <process field="firstName">
                      <copy/>
                      <not-empty>
                          <fail-property property="PracticeFirstNameMissingError" resource="PracticeUiLabels"/>
                      </not-empty>&nbsp;&nbsp;&nbsp;
                  </process>
              </simple-map-processor>
          </call-map-processor>
          <check-errors/>
          

      ...

        1. Create some Ui labels for showing them in fail-property like PracticeFirstNameMissingError.

      ...

        1. Now call service createPracticePerson service by passing out map which is obtained after processing fields as a in map to the service.
          OutPut Screen :
          Image Modified

      Java Event

      Here the java event which you will be writing will be fairly simple. For reference you can check any of the *Events.java file. Step - 1 :

      1. The contents will be :
        Code Block
        
        public static String createPracticePersonJavaEvent(HttpServletRequest request, HttpServletResponse response){
            LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
            GenericDelegator delegator = (GenericDelegator) request.getAttribute("delegator");
        }
        

      ...

      1. Now you have to process the fields comming from the form like
        Code Block
        
        String salutation = (String) request.getParameter("salutation");
        String firstName = (String) request.getParameter("firstName");
        

      ...

      1. Now prepare a map for the values which you have to pass to the service which you will call "createPracticePerson" . Like
        Code Block
        
        Map createPersonCtx = UtilMisc.toMap("salutation", salutation, "firstName", firstName);
        

      ...

      1. Then at the end just call the service "createPracticePerson" like
        Code Block
        
        try{
            Map person = dispatcher.runSync("createPracticePerson", createPersonCtx);
         }catch (GenericServiceException e){
             Debug.logError(e.toString(), module);
             return "error";
         }
        return "success";
        
        After writting event in Java don't forget to compile it by running "ant" command. At this moment you will need to add build.xml file to your component directory i.e. at hot-deploy/practice/ For the content of build.xml file you can refer "example" component.
        Here in build.xml file ensure one thing you are having follwing entry:
        Code Block
        
        <target name="classpath">
            <path id="local.class.path">
                <fileset dir="../../framework/base/lib/j2eespecs" includes="*.jar"/>
            </path>
        </target>
        
        This will needed for the classes like
        Code Block
        
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        
        So create a file by name build.xml and then compile it. It will create a build directory in your component directory which will be containing all *.jar and class files after compilation. For the content of build.xml file you can refere example component. 
        For running the simple event don't forget to make an entry for <classpath type="dir" location="script"/> in ofbiz-component.xml file.
        For running the java event make an entry <classpath type="jar" location="build/lib/*"/> in ofbiz-component.xml file.

      Part 4

      ECA(Event Condition Action)

      ECA : It is a combinition of 3 things: an event, conditions per event, and actions per event. It is a rule used to trigger an action upon the execution of an event when certain conditions are met. When a service is called for example a lookup is performed to see if any ECAs are defined for this event. Events include before authentication, before IN parameter validation, before actual service invocation, before OUT parameter validation, before transaction commit, or before the service returns. Next, each condition in the ECA definition is evaluated and if all come back as true, each action is performed. An action is just a service which must be defined to work with the parameters already in the service's context. There is no limit to the number of conditions or actions each ECA may define.
      For more details on this visit :  Service Engine Guide 1.

      1. SECA (Service Event Condition Action) : This is used when we want to trigger another service(action) on the execution of a service when certain conditions are met

      ...

      1. .
      2. EECA (Entity Event Condition Action) : This is used when we want to trigger a service on the creation of a record for an entity when certain conditions are met.
        For the implementation of ECA again we will be following the same approach for screens, menus by following steps:

      ...

      1. Add one more application menu named "ECA" to the practice application's menu bar.(Do the needful entries for target in controller.xml)

      ...

      1. Now create another menu called "EcaMenu" in the PracticeMenus.xml file. This menu will have two menu items named "seca" and "eeca". For each of these, two screens will be needed that use the "CreatePerson" form which we created above. (in personForm screen)
        Code Block
        
        <menu name="EcaMenu" default-menu-item-name="seca" default-selected-style="selected"
               type="simple" menu-container-style="button-bar button-style-2" selected-menuitem-context-field-name="headerItem">
              <menu-item name="seca" title="Create Person --- SECA">
                  <link target="seca"/>
              </menu-item>
              <menu-item name="eeca" title="Create Person --- EECA">
                  <link target="eeca"/>
              </menu-item>   
        </menu>
        

      SECA

      ...

      1. For this you have to write another service by name "createPartyRoleVisitor",  which will be setting the role for the party which will be created by "createPracticePerson" service.
        The service "createPartyRoleVisitor" will be triggered by the seca rule which you will define for service "createPracticePerson".
        In the new service involved entity will by "PartyRole". In "createPartyRoleVisitor" just call service "createPartyRole" which is already implemented.

      ...

      1. Now you have to create a file by name "secas.xml" in "servicedef" directory. Seca definition will come here. (Take reference from secas.xml of "party" component). This will be
        Code Block
        
        <eca service="createPracticePerson" event="commit">
            <condition field-name="partyId" operator="is-not-empty"/>
            <action service="createPartyRoleVisitor" mode="sync"/>
        </eca>
        

      ...

      1. Do an entry in ofbiz-component.xml file for this seca definition to to be loaded. It will be :
        <service-resource type="eca" loader="main" location="servicedef/secas.xml"/>
        Don't forget to restart the server after doing this entry.
        Now run the service through form and check the records in PartyRole entity. You will find a role is set for the party created because synchrounously you have triggered another service by seca rule for setting up the role for the party created.

      EECA

      ...

      1. For this you have to write another service by name "createPartyRoleCustomer",  which will be setting the role for the party which will be created means when a record for the entity "Party" will be created this service will be triggered for setting a role customer for that party. The service "createPartyRoleCustomer" will be similar to "createPartyRoleVisitor".

      ...

      1. Now you have to create a file by name "eecas.xml" in "entitydef" directory, which will be in your component directory "practice". Eeca definition will come here. (Take reference from eecas.xml of "accounting" component). This will be :
        Code Block
        
        <!-- To create party role whenever a party is created -->
        <eca entity="Party" operation="create" event="return">
            <condition field-name="partyId" operator="is-not-empty"/>
            <action service="createPartyRoleCustomer" mode="sync"/>
        </eca>
        

      ...

      1. Do an entry in ofbiz-component.xml file for this seca definition to to be loaded. It will be :
        Code Block
        
        <entity-resource type="eca" reader-name="main" loader="main" location="entitydef/eecas.xml"/>
        
        Don't forget to restart the server after doing this entry.
        Now run the service through form and check the records in PartyRole entity. You will find a role is set for the party created because synchrounously you have triggered a service by eeca rule for setting up the role for the party created.
        The main difference here is that you are triggering a service when an operation is performed on the entity. In our case it is "create".
        Note Here you have created a saparate menu to understand the concept separately. As you written seca for the service "createPracticePerson", so where ever in your practice application you will be calling this service that seca will trigger "createPartyRoleVisitor" and on the other hand when a party will be created "createPartyRoleCustomer" will be triggered.
        Output Screen :
        Image Modified
         

      Group Service

          Group services are used to call more then one services as a group. Service groups are a set of services which should run when calling the initial service. You define a service using the group service engine, and include all the parameters/attributes needed for all the services in the group. The location attribute is not needed for groupservices, the invoke attribute defines the name of the group to run. When this service is invoked the group is called and the services defined in the group are called as defined.
      For mor details on this visit :http://docs.ofbiz.org/display/OFBTECH/Service+Engine+Guide
      For the implementation of Group service follow these steps: Step - 1 :

      1. Add another menu item to applicatoin menu bar by name "Group Service".(Do the needful entries for target in controller.xml)

      ...

      1. Now create new screen and a form for creation of the person because the target for the form will be the group service which we will be defining.
        Note : Now the time is to define the group service. We will be defining the group service for the services which we have implemented for this practice application.

      ...

      1. You will be defining the service group in services.xml file.(Take reference from services.xml of party component).
        Just write one more service which will be setting the role "CLIENT" for the party which will be created by createPracticePerson Service. 
         Create a group service by name "partyGroup" like :
        Code Block
        
        <!-- Group service -->
        <service name="partyGroup" engine="group" auth="true">
            <description>Creates a party, person and party role Client</description>
            <group>
                <invoke name="createPracticePerson" result-to-context="true"/>
                <invoke name="createPartyRoleClient"/>
            </group>
        </service>
        
        Don't forget to restart the server before testing it. 

      Interface

      The interface service engine has been implemented to help with defining services which share a number of the same parameters. An interface service cannot be invoked, but rather is a defined service which other services inherit from. Each interface service will be defined using the interface engine.
      For more details on this visit :  http://docs.ofbiz.org/display/OFBTECH/Service+Engine+Guide
      For implemeting the interface follow these steps: Step - 1 :

      1. Add another menu item to applicatoin menu bar by name "Interface".(Do the needful entries for target in controller.xml)

      ...

      1. Create new screen, form and service for creating a person. Here service will implement the interface. (For creating interface take reference from services_fixedasset.xml of accounting component) it will be like :
        Code Block
        
        <!-- Peson Interface -->
        <service name="createPersonInterface" engine="interface" location="" invoke="">
            <attribute name="firstName" mode="IN" type="String" optional="false"/>
            <attribute name="middleName" mode="IN" type="String" optional="true"/>
            <attribute name="lastName" mode="IN" type="String" optional="false"/>
            <attribute name="suffix" mode="IN" type="String" optional="true"/>
        </service>
        <service name="createPracticePersonInterfaceService" engine="simple"
                location="org/hotwax/practice/PracticeServices.xml" invoke="createPracticePersonInterfaceService" auth="false">
            <description>Creates a new Person</description>
            <implements service="createPersonInterface"/>
            <attribute name="partyId" mode="OUT" type="String" optional="false"/>
            <override name="suffix" optional="false"/>
        </service>
        
        Here we are implementing an interface and overriding the behaviour of the attribute "suffix", which will have effect when this service will be in action.
        Implementation of service createPracticePersonInterfaceService will be the same as createPracticePerson.
        Don't forget to restart the server after this implementation.

      Part 5

      Creating Custom Entity

       For the creation of new entity you can again take a referecne from example component for this you can have a look in entitymodel.xml file of example component. You can create new entities by following these steps: Step - 1 :

      1. Create a new subdirectory by name entitydef in hot-deploy/practice/.

      ...

      1. Create new file by name  entitymodel.xml. This file will contain the defintions of entities which you want to define.

      ...

      1. For loading the defintion you need to do an entry in your ofbiz-component.xml file like:
        Code Block
        
        <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel.xml"/>
        
        That implies that when ever you do a change you need to restart the server to have those changes in effect.
        At this place an important reading is at http://docs.ofbiz.org/display/OFBTECH/General+Entity+Overview.
        You will rarely find this way to define new entity because you are already having entities there in OFBiz already defined which will be useful for the conduction of your business process. Though you may feel at some place to add more fields to an existing entity so how can you do that? The next  step will show you the way how you can extend an entity for your customized needs.
        Earlier we used to have one more file in same directory by name entitygroup.xml which not needed any more because code is checked in to the trunk for this.

      Extending an Existing OOTB Entity

      Yes you can extend an existing entity for adding more fields to for your custom needs. This can be done in following way: Step - 1 : 

      1. For extending an entity you can do in this manner in the entitydef/entitymodel.xml file of your custom application.
        Code Block
        
        <extend-entity entity-name="">
            <field name="" type=""/>
        </extend-entity>
        
        As an example of this you can refer entitymodel.xml file from party component.
        This is the simplest form it can be more complex. This will add up one more field to the entity you already have. Now it depends which field you want for your custom needs. Here you can also defined relation of this field with other entities you want. But before doing this you should search extesively may be you will be adding a field for a purpose and there is already a field which will serve the purpose, so be concisous about this. Also go for a extensive study of data model then do this.
        For entity engine configuration dont forget to read : Entity Engine Configuration Guide

      Preparing Data For Custom Application

       For preparing data for your practice application following steps can be performed: Step - 1 :

      1. Create new folder in practice by name "data" and create a file in it by name PracticeData.xml.

      ...

      1. Now we are going to create the data for a user for this we have to prepare it in a specific order for a party like :
        Code Block
        
        <?xml version="1.0" encoding="UTF-8"?>
        <entity-engine-xml>
            <Party partyId="DemoUser" partyTypeId="PERSON"/>
            <Person partyId="DemoUser" firstName="Practice" lastName="Person"/>
            <PartyRole partyId="DemoUser" roleTypeId="VISITOR"/>
            <ContactMech contactMechId="5000" contactMechTypeId="EMAIL_ADDRESS" infoString="practice.person@gmail.com"/>
            <PartyContactMech partyId="DemoUser" contactMechId="5000" fromDate="2001-05-13 00:00:00.000" allowSolicitation="Y"/>
            <PartyContactMechPurpose partyId="DemoUser" contactMechId="5000" contactMechPurposeTypeId="PRIMARY_EMAIL" fromDate="2001-05-13 00:00:00.000"/>
        </entity-engine-xml>
        
        The purpose is to create a record for a party who is a person with a role of VISITOR and creating an email address which is a primary email address for that party.

      ...

      1. Now also add website data here which is as follows:
        Code Block
        
        <WebSite webSiteId="PRACTICE" siteName="Practice Application" visualThemeSetId="BACKOFFICE"/>
      2. This data is used for theme setup of a specific application and logged in user can change his theme for the back office application.

      ...

      1. Now we have to an entry in ofbiz-component.xml file :
        Code Block
        
        <entity-resource type="data" reader-name="demo" loader="main" location="data/PracticeData.xml"/>
        
        After doing this entry when you will run the command ant run-install to load demo data then the data from this file will be loaded as demo data and once you start the server you can see this record added for person by going to Person Form in practice application or you can prefer to go to https://localhost:8443/webtools/control/entitymaint and find each entity and check the records have gone in the database or not.

      Part 6

      Info
      titleImportant!

      This part of the tutorial doesn't work with the latest version of Ofbiz. You can find informations about Ajax Request with this version in the Example component (tab Ajax Examples).

      ...

      Now lets start with Coding part:Step - 1 :

      1. Make entry of /js in allowedPaths of web.xml. So now allowed paths parameter will look like given below:
        1. This will allow .js files which are under /js folder to load.
        2. Step -7 will make you understand more, why we are doing this entry here.
          Code Block
          
          <init-param>
              <param-name>allowedPaths</param-name>
              <param-value>/control:/select:/index.html:/index.jsp:/default.html:/default.jsp:/images:/includes/maincss.css:/js</param-value>
          </init-param>
          
          *Note: * Here you must not miss that this will require a server restart.

      ...

      1. Include validation.js and prototype.js in main-decorator in practice/widget/CommonScreens.xml. For this you have to write below given code in <actions> block of main-decorator.
        1. We are including these library files in main-decorator screen, because all other screens uses main-decorator and thus both the libraries will be available in other screens as well.
          Code Block
          
          <set field="layoutSettings.javaScripts[+0]" value="/images/prototypejs/validation.js" global="true"/>
          <set field="layoutSettings.javaScripts[]" value="/images/prototypejs/prototype.js" global="true"/>
          
          validation.js and prototype.js are located at framework/images/webapp/images/prototypejs/

      ...

      1. Add another menu item to application menu bar by name "Ajax". Below given is the controller entry:
        Code Block
        
        <!-- Request Mapping -->
        

      ...

      1. <request-map uri="Ajax">
            <security https="true" auth="true"/>
            <response name="success" type="view" value="PersonFormByAjax"/>
        </request-map>
        
        <!-- View Mapping -->
        

      ...

      1. <view-map name="PersonFormByAjax" type="screen" page="component://practice/widget/PracticeScreens.xml#PersonFormByAjax"/>
        

      ...

      1. Create new screen called "PersonFormByAjax" in PracticeScreens.xml. Example code is given below:
        1. PracticeApp.js is the custom js file where we will be writing our custom js code for ajaxifying our request.
        2. person.ftl is the same file we created above.
        3. CreatePerson.ftl is a new file which you need to create now. This file contains form for creating new person, which is same as we created in step-1 of Part-3 under "Writing CrUD operations for Person entity" section. Only difference is that this form is written in freemarker.
          Code Block
          
          <screen name="PersonFormByAjax">
              <section>
                  <actions>
                      <set field="headerItem" value="ajax"/>
                      <set field="titleProperty" value="PageTitlePracticePersonForm"/>
                      <property-map resource="PartyUiLabels" map-name="uiLabelMap" global="true"/>
                      <set field="layoutSettings.javaScripts[]" value="/practice/js/PracticeApp.js" global="true"/>
                      <entity-condition entity-name="Person" list="persons"/>
                  </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-template location="component://practice/webapp/practice/CreatePerson.ftl"/>
                                  </html>
                              </platform-specific>
                          </decorator-section>
                      </decorator-screen>
                  </widgets>
              </section>
          </screen>
          

      ...

      1. Create new file CreatePerson.ftl explained above in practice/webapp/practice/ and place below given code:
        1. Also notice ids used in this .ftl file.
        2. We will be using these ids in our js file.
          Code Block
          
          <h2>${uiLabelMap.PartyCreateNewPerson}</h2>
          <div id="createPersonError" style="display:none"></div>
          <form method="post" id="createPersonForm" action="<@ofbizUrl>createPracticePersonByAjax</@ofbizUrl>">
            <fieldset>
              <div>
                <label>${uiLabelMap.FormFieldTitle_salutation}</label>
                <input type="text" name="salutation" value=""/>
              </div>
              <div>
                <label>${uiLabelMap.PartyFirstName}*</label>
                <input type="text" name="firstName"  value=""/>
              </div>
              <div>
                <label>${uiLabelMap.PartyMiddleName}</label>
                <input type="text" name="middleName" value=""/>
              </div>
              <div>
                <label>${uiLabelMap.PartyLastName}*</label>
                <input type="text" name="lastName" class="required" value=""/>
              </div>
              <div>
                <label>${uiLabelMap.PartySuffix}</label>
                <input type="text" name="suffix" value=""/>
              </div>
              <div>
                <a id="createPerson" href="javascript:void(0);" class="buttontext">${uiLabelMap.CommonCreate}</a>
              </div>
            </fieldset>
          </form>
          
        3. Click on "Ajax" menu to observe the PersonFormByAjax screen.

      ...

      1. Add new div in person.ftl file. Now person.ftl will look like:
        1. Here again div's id will be used in PracticeApp.js file
          Code Block
          
          <#if persons?has_content>
            <div id="personList">
              <h2>Some of the people who visited our site are:</h2>
              <br>
              <ul>
                <#list persons as person>
                  <li>${person.firstName!} ${person.lastName!}</li>
                </#list>
              </ul>
            </div>
          </#if>
          

      ...

      1. Now create PracticeApp.js in practice/webapp/practice/js/ and place the below given code :
        1. Here on first line, Event.observe(element, eventName, handler), registers an event handler on a DOM element.
          1. Argument 1: The DOM element you want to observe; as always in Prototype, this can be either an actual DOM reference, or the ID string for the element.
          2. Argument 2: The standardized event name, as per the DOM level supported by your browser. This can be as simple as 'click'.
          3. Argument 3: The handler function. This can be an anonymous function you create on-the-fly, a vanilla function.
        2. So here on window load, on-the-fly function is called. where form validations and request calling is done.
        3. Important thing to notice is why we write other observation code on window load event, and answer is here we keep restriction, that on window load, all the elements of the form will get activated and then we put observation on form's elements.
        4. In CreatePerson.ftl you see that class="required" are used on forms's input element, You then activate validation by passing the form or form's id attribute as done in second line. More on this can be learned from learn validation
        5. On third line, observer is on "createPerson" which is id of anchor tag (button) in CreatePerson.ftl,
        6. so that when end user clicks "create button" , the instance method, validate(), will return true or false. This will activate client side validation.
        7. And then createPerson function is called which is out of the scope of window load observer.
        8. In request variable, createPersonForm's action is stored. $('createPersonForm') is again a id of form in CreatePerson.ftl.
        9. new Ajax.Request(url) : Initiates and processes an AJAX request.
        10. The only proper way to create a requester is through the new operator. As soon as the object is created, it initiates the request, then goes on processing it throughout its life-cyle.
        11. Request life cycle:
          1. Created
          2. Initialized
          3. Request sent
          4. Response being received (can occur many times, as packets come in)
          5. Response received, request complete
        12. So here createPracticePersonByAjax request will be called from controller.xml, which will call createPracticePerson service and do needful entries.
        13. Form's elements are serialized and passed as a parameter in ajax request. This is represented in last line of createPerson function.
        14. Now if response is successful and server has not returned an error, "new Ajax.Updater($('personList'), 'UpdatedPersonList'" will be executed.
        15. Ajax updater, performs an AJAX request and updates a container's contents based on the response text. To get more on this please read : ajax updater
        16. So "personList" is the id of div in person.ftl, which will be replaced by response of UpdatedPersonList request.
          Code Block
          
          Event.observe(window, 'load', function() {
              var validateForm = new Validation('createPersonForm', {immediate: true, onSubmit: false});
              Event.observe('createPerson', 'click', function() {
                 if (validateForm.validate()) {
                     createPerson();
                 }
              });
          });
          
          function createPerson() {
              var request = $('createPersonForm').action;
              new Ajax.Request(request, {
                  asynchronous: true,
                  onComplete: function(transport) {
                      var data = transport.responseText.evalJSON(true);
                      var serverError = getServerError(data);
                      if (serverError != "") {
                          Effect.Appear('createPersonError', {duration: 0.0});
                          $('createPersonError').update(serverError);
                      } else {
                          Effect.Fade('createPersonError', {duration: 0.0});
                          new Ajax.Updater($('personList'), 'UpdatedPersonList', {evalScripts: true});
                      }
                  }, parameters: $('createPersonForm').serialize(), requestHeaders: {Accept: 'application/json'}
              });
          }
          

      ...

        1. getServerError = function (data) {
              var serverErrorHash = [];
              var serverError = "";
              if (data._ERROR_MESSAGE_LIST_ != undefined) {
                  serverErrorHash = data._ERROR_MESSAGE_LIST_;
          
                  serverErrorHash.each(function(error) {
                      if (error.message != undefined) {
                          serverError += error.message;
                      }
                  });
                  if (serverError == "") {
                      serverError = serverErrorHash;
                  }
              }
              if (data._ERROR_MESSAGE_ != undefined) {
                  serverError += data._ERROR_MESSAGE_;
              }
              return serverError;
          };
          

      ...

      1. Now do required controller.xml entries :
        1. Here you may see that after service invocation request is chained and and is redirected to json request.
        2. json request is in common-controller.xml which invokes common json reponse events and send back json reponses.
          Code Block
          
          <request-map uri="createPracticePersonByAjax">
              <security https="true" auth="true"/>
              <event type="service" invoke="createPracticePerson"/>
              <response name="success" type="request" value="json"/>
              <response name="error" type="request" value="json"/>
          </request-map>
          <request-map uri="UpdatedPersonList">
              <security https="true" auth="true"/>
              <response name="success" type="view" value="UpdatedPersonList"/>
          </request-map>
          <!--View Mappings -->
          <view-map name="UpdatedPersonList" type="screen" page="component://practice/widget/PracticeScreens.xml#UpdatedPersonList"/>
          

      ...

      1. Finally create UpdatedPersonList screen in practice/widget/PracticeScreens.xml
        1. This is same as Person Screen
        2. Now this screen will be shown by Ajax updater.
          Code Block
          
          <screen name="UpdatedPersonList">
              <section>
                  <actions>
                      <script location="component://practice/webapp/practice/WEB-INF/actions/person.groovy"/>
                  </actions>
                  <widgets>
                      <platform-specific>
                          <html>
                              <html-template location="component://practice/webapp/practice/person.ftl"/>
                          </html>
                      </platform-specific>
                  </widgets>
              </section>
          </screen>
          

      ...

      1. Now submit the form and and run your ajax request.
      Note
      1. One important thing to remember is "id" used in form should always be unique. And if you use same id on different elements then prototype may get confused and your javascript will be blocked. these can well observed using firbug.
      2. Also installation of firebug is suggested from get firebug, for debugging javascript in Mozilla.

      Next Steps

      If you have followed all the steps and developed practice application from this tutorial then this will really help you in understanding other implementation in OFBiz. These things are basic foundation of working in OFBiz. Now you know, how you can start the development in OFBiz. Don't leave the extra links provided in this tutorial as they will really help you a lot in understanding the things which are there in detail.
      Here is another good reading will be help you a lot is available at FAQ Tips Tricks Cookbook HowTo
      Now the next thing comes in the way is the business processes which are really needed to be read out for understanding OOTB process flow in OFBiz and OOTB data model, so for this, books are available at : OFBiz Related Books.

      ...