Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Part-6 is introduced 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.
Important!
This tutorial is intended to be used with the latest SVN revision. It will not work with Release 4.
You can watch OFBiz videos, which are available at Framework Introduction Videos, in parallel with the development of
this application.
Part - 1
Note - 1 :- For any additional queries and concerns you can refer Example component. You will always find the code in
example component to be the latest code of OFBiz. Take reference whenever you want to see some sample code for the
development of this application, this will help you in future developments as well.
Every new feature is first added in the Example component for the references.
Note - 2 : Before starting the development of this application you must read the contents from:
OFBiz Contributors Best Practices , Coding Conventions and Best Practices Guide
Note - 3 : Don't copy any file from other component, as the revision number for the file is also copied. Always create a
new file and, if required, then copy the contents of the file." Also be conscious about the unused code as well.
Note - 4 : For searching any of the document the best place is at : OFBiz Documentation Index.
Note - 5 : Right from the beginning, reading the console log must be a habit to make troubleshooting easy and
understanding the system well.
Note - 6 : You can find the source code of this application attached with this document that you are going to develop but
it is preferred to just take reference from it
ofbiz-component.xml explained:
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.
<webapp name="practice"
title="Practice"
server="default-server"
base-permission="OFBTOOLS"
location="webapp/practice"
mount-point="/practice"
app-bar-display="false"/>
<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
</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
</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; refe
</context-param>
For now just put websiteId as "PRACTICE", you will explanation after some time in this tutorial only.
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
${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.
Step - 5 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:
Step - 6 : Move up one level and create a new directory named 'error'(hot-deploy/practice/webapp/practice/error).
Step - 6.a : 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.
Step - 7 : 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.
Step - 8 : 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 . On this page there links to following:
HTML and CSS Best Practices
Managing Your Source Differences
Methodology Recommendations
User Interface Layout Best Practices
All these readings will be really of help.
Very first screen will be like :
Step - 9 : 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.
Step - 10 : 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 :
Step - 11 : 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
<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.
Step - 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.
<?xml version="1.0" encoding="UTF-8"?>
<menus xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocati
<menu name="MainAppBar" title="PracticeApplication" extends="CommonAppBarMenu" exten
<menu-item name="main" title="Main"><link target="main"/></menu-item>
</menu>
</menus>
<screen name="CommonPracticeDecorator">
<section>
<widgets>
<include-menu location="component://practice/widget/PracticeMenus.xml"
<decorator-section-include name="body"/>
</widgets>
</section>
</screen>
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?
Step - 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:
<#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>
Step - 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:
<screen name="person">
<section>
<actions>
<script location="component://practice/webapp/practice/WEB-INF/actions/P
</actions>
<widgets>
<decorator-screen name="CommonPracticeDecorator" location="${parameters.
<decorator-section name="body">
<platform-specific>
<html>
<html-template location="component://practice/webapp/pra
</html>
</platform-specific>
</decorator-section>
</decorator-screen>
</widgets>
</section>
</screen>
Step - 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 .
Hint
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)
Step - 1 : Now add one more menu item to by name "PersonForm" to your PracticeMenus.xml file.
Step - 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).
<form name="ListPersons" type="list" list-name="persons" list-entry-name="person" targe
<auto-fields-service service-name="updatePracticePerson" default-field-type="dis
</form>
Step - 3 : Create new screen by name personForm and include this list form in it.
<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.
<decorator-section name="body">
<label text="Person List" style="h2"/>
<include-form name="ListPersons" location="component://practice/
</decorator-section>
</decorator-screen>
</widgets>
</section>
</screen>
<screen name="main-decorator">
<section>
<actions>
<property-map resource="CommonUiLabels" map-name="uiLabelMap" global=
<property-map resource="PracticeUiLabels" map-name="uiLabelMap" global=
<set field="layoutSettings.companyName" from-field="uiLabelMap.PracticeC
<set field="activeApp" value="practice" global="true"/>
<set field="applicationMenuName" value="PracticeAppBar" global="true"
<set field="applicationMenuLocation" value="component://practice/widget/
</actions>
<widgets>
<include-screen name="GlobalDecorator" location="component://common/widg
</widgets>
</section>
</screen>
Step - 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 :
Step - 1 : 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:
*Step - 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 :
That means you have to place the config directory on the classpath to access configuration files.
Step - 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
<property key="PracticeApplication">
<value xml:lang="en">This is first practice</value>
</property>
<property key="PracticeCompanyName">
<value xml:lang="en">OFBiz: Practice</value>
</property>
Step - 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.Step - 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:
Now its time to make this practice application secure by checking
authentication (user login):
Step - 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
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:
Step - 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 :
<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.
Step : 1 - Login into partymanager to confirm that the user admin has the required permission
https://127.0.0.1:8443/partymgr/control/main
Step : 2 - Once your logged in search for the user by typing 'admin' in the User Login field and then clicking the Lookup
Party button.
Step : 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 logins as listed in the
User Name(s) form.
Step : 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.
Step : 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'
Step : 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
<request-map uri="createPracticePerson">
<security https="true" auth="true"/>
<event type="service" invoke="createPracticePerson"/>
<response name="success" type="view" value="PersonForm"/>
</request-map>
Step - 3: 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
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://www.nabble.com/The-fancy-new-entity-auto-service-execution-engine-
td18674040.html. 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.
Step - 2 : Write CrUD operations for person entity.this is a code for createPracticePerson in services.xml
<service name="createPracticePerson" default-entity-name="Person" engine="simple"
location="component://practice/script/org/hotwax/practice/PracticeServices.xml
<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>
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.
Step - 4 : 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.
Step - 5 : 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 :
<request-map uri="createPracticePersonSimpleEvent">
<security https="true" auth="true"/>
<event type="simple" path="component://practice/script/org/hotwax/practice/PracticeE
<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:
<request-map uri="createPracticePersonJavaEvent">
<security https="true" auth="true"/>
<event type="java" path="org.hotwax.practice.PracticeEvents" invoke="createPracticeP
<response name="success" type="view" value="CreatePracPersonJavaEvent"/>
<response name="error" type="view" value="CreatePracPersonJavaEvent"/>
</request-map>
Simple Event
Step - 6 : Now in the script/org/hotwax/practice/ create one file by name PracticeEvents.xml.
Step - 7 : 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:
7.a : Process fields coming from the form like:
7.b : Create some Ui labels for showing them in fail-property like PracticeFirstNameMissingError.
7.c : Now call service createPracticePerson service by passing out map which is obtained after processing fields as a in
map to the service.
OutPut Screen :
Part - 4
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 : The contents will be :
Step - 2 : Now you have to process the fields comming from the form like
Step - 3 : Now prepare a map for the values which you have to pass to the service which you will call
"createPracticePerson" . Like
Step - 4 : Then at the end just call the service "createPracticePerson" like
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:
<target name="classpath">
<path id="local.class.path">
<fileset dir="../../framework/base/lib/j2eespecs" includes="*.jar"/>
</path>
</target>
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.
SECA :
Step - 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.
Step - 2 : 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
Step - 3 : 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 :
Step - 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".
Step - 2 : 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 :
Step - 3 : Do an entry in ofbiz-component.xml file for this seca definition to to be loaded. It will be :
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 : Add another menu item to applicatoin menu bar by name "Interface".(Do the needful entries for target in
controller.xml)
Step - 2 : 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 :
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
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.
<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
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.
Step - 3 : Now also add website data here which is as follows:
This data is used for theme setup of a specific application and logged in user can change his theme for the back office
application.
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
In OFBiz we use prototype framework. Prototype is a Open Source JavaScript Framework that aims to ease development
of dynamic web applications. Here is the official link: prototypejs
Step - 1 : Make entry of /js in allowedPaths of web.xml. So now allowed paths parameter will look like given below:
This will allow .js files which are under /js folder to load.
Step -7 will make you understand more, why we are doing this entry here.
<init-param>
<param-name>allowedPaths</param-name>
<param-value>/control:/select:/index.html:/index.jsp:/default.html:/default.jsp:/ima
</init-param>
Here you must not miss that this will require a server restart.
Step - 2 : 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.
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.
Step - 3 : Add another menu item to application menu bar by name "Ajax". Below given is the controller entry:
<request-map uri="Ajax">
<security https="true" auth="true"/>
<response name="success" type="view" value="PersonFormByAjax"/>
</request-map>
Step - 4 : Create new screen called "PersonFormByAjax" in PracticeScreens.xml. Example code is given below:
PracticeApp.js is the custom js file where we will be writing our custom js code for ajaxifying our request.
person.ftl is the same file we created above.
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.
<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
<entity-condition entity-name="Person" list="persons"/>
</actions>
<widgets>
<decorator-screen name="CommonPracticeDecorator" location="${parameters.main
<decorator-section name="body">
<platform-specific>
<html>
<html-template location="component://practice/webapp/practic
<html-template location="component://practice/webapp/practic
</html>
</platform-specific>
</decorator-section>
</decorator-screen>
</widgets>
</section>
</screen>
Step - 5 : Create new file CreatePerson.ftl explained above in practice/webapp/practice/ and place below given code:
<h2>${uiLabelMap.PartyCreateNewPerson}</h2>
<div id="createPersonError" style="display:none"></div>
<form method="post" id="createPersonForm" action="<@ofbizUrl>createPracticePersonByAjax<
<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.Co
</div>
</fieldset>
</form>
Step - 6 : Add new div in person.ftl file. Now person.ftl will look like:
Step - 7 : Now create PracticeApp.js in practice/webapp/practice/js/ and place the below given code :
Here on first line, Event.observe(element, eventName, handler), registers an event handler on a DOM element.
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.
Argument 2: The standardized event name, as per the DOM level supported by your browser. This can be
as simple as 'click'.
Argument 3: The handler function. This can be an anonymous function you create on-the-fly, a vanilla
function.
So here on window load, on-the-fly function is called. where form validations and request calling is done.
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.
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
On third line, observer is on "createPerson" which is id of anchor tag (button) in CreatePerson.ftl,
so that when end user clicks "create button" , the instance method, validate(), will return true or false. This will
activate client side validation.
And then createPerson function is called which is out of the scope of window load observer.
In request variable, createPersonForm's action is stored. $('createPersonForm') is again a id of form in
CreatePerson.ftl.
new Ajax.Request(url) : Initiates and processes an AJAX request.
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.
Request life cycle:
Created
Initialized
Request sent
Response being received (can occur many times, as packets come in)
Response received, request complete
So here createPracticePersonByAjax request will be called from controller.xml, which will call
createPracticePerson service and do needful entries.
Form's elements are serialized and passed as a parameter in ajax request. This is represented in last line of
createPerson function.
Now if response is successful and server has not returned an error, "new Ajax.Updater($('personList'),
'UpdatedPersonList'" will be executed.
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
So "personList" is the id of div in person.ftl, which will be replaced by response of UpdatedPersonList request.
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:
}
}, parameters: $('createPersonForm').serialize(), requestHeaders: {Accept: 'appl
});
}
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;
};
Here you may see that after service invocation request is chained and and is redirected to json request.
json request is in common-controller.xml which invokes common json reponse events and send back json
reponses.
<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/Pract
<screen name="UpdatedPersonList">
<section>
<actions>
<script location="component://practice/webapp/practice/WEB-INF/actions/
</actions>
<widgets>
<platform-specific>
<html>
<html-template location="component://practice/webapp/practice/p
</html>
</platform-specific>
</widgets>
</section>
</screen>
Step - 10: Now submit the form and and run your ajax request.
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.
Also installation of firebug is suggested from get firebug, for debugging javascript in Mozilla.
Conclusion:
If you have followed all the steps and developed practice application from this tutorial then this will really help you in
understanding other implementations in OFBiz. These things are basic foundation of working in OFBiz. Now you know
that 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.
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 mind is the business process which is really needed to read out for understanding OOTB
implemention in OFBiz, flow of these processes and data model, so for this, books are available at : OFBiz Related
Books. Here you can also find books other than business processes.
Now you are ready to dive in. Welcome to OFBiz world.
–
Pranay Pandey
Comments (17)
"Writing CRUD operations" paragraph should be updated in regard of new attribute entity-auto
http://www.nabble.com/The-fancy-new-entity-auto-service-execution-engine-td18674040.html
Thanks Jacques for pointing this thing out. I have added the example and description for this new
feature at the place.
Thanks Again
--
Pranay Pandey
You might be interested by this tutorial too. It's about how to set security and permissions precedence.
Thanks to you Jacques for this link and Thanks to Milind for creating this document. I have also
updated this tutorial for this implementation.
Regards
--
Pranay Pandey
Hi Pranay,
I found that I had to add the following line to the controller.xml file to get Part 1 working:
<handler name="screen" type="view" class="org.ofbiz.widget.screen.ScreenWidgetVi
Kind Regards
Andy
Hi Andy,
I think you forgot to include common-controller.xml file in your controller.xml file like:
<include location="component://common/webcommon/WEB-INF/common-controller.xml"/>
All handlers are available form that common-controller.xml file. If you don't include that in your
controller then you need to provide these handlers explicitly. Not only ScreenWidgetViewHandler but
all the handlers which are needed to run your application.
Pranay,
Thank you very much for the tutorial. I had the same issue stated by Andy with the following error
message:
Regards,
CJ
If you are not getting the common-controller.xml file at the stated location then thats a problem which
needs concentration.
This needs to be cleared that if you don't include this controller then only you need to explicitly go for
including handlers in your controller.xml file.
in part2's "Doing some advancements", step5 says: "Now create a new screen by name "person" in
PracticeScreens.xml file and also create a new menu item in PracticeMenus.xml file."
1. I have no idea about how to create a new screen and what contents should I put into the newly-
created screen.
2. how to create a new menu item in PracticeMenus.xml, and what contents should I put into?
3. how can I make the new menu item in PracticeMenus.xml with the screen with name of "person"?
sections order:
</field>
</service>
</field>
</service>
But i get null value only. How can i get the correct value entered in the form
I've been searching around for two days to get screen widgets to work, with no luck. After completing step
6 of part 2 I run the request in my browser and get the following error.
I can't find much information on how widgets work in OFBiz. Any help would be much appreciated.
Thanks
Jacques
I too had difficultly getting the sample to work. My problem, as it turned out, was that I had used the wrong
web.xml to build upon. I was able to get it to work by using the examplext's web.xml, and then replacing
those two fragments specified in the documentation (i.e., replace the fragments using
localDispatcherName and mainDecoratorLocation).
The following link may be useful if you want to provide helpful tooltips in your forms -
http://cwiki.apache.org/confluence/x/jgE7AQ
Here is what I came up with after many struggles. It works, just not sure if it's the best.
From PracticeServices.xml:
Powered by a free Atlassian Confluence Open Source Project License granted to Apache Software Foundation. Evaluate
Confluence today.