...
Code Block |
---|
|
<?xml version="1.0" encoding="UTF-8"?>
<entitymodel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/entitymodel.xsd">
<title>Entity of an Open For Business Project Component</title>
<description>None</description>
<version>1.0</version>
<entity entity-name="OfbizDemoType" package-name="org.ofbiz.ofbizdemo" title="OfbizDemo Type Entity">
<field name="ofbizDemoTypeId" type="id-ne"><description>primary sequenced ID</description></field>
<field name="description" type="description"></field>
<prim-key field="ofbizDemoTypeId"/>
</entity>
<entity entity-name="OfbizDemo" package-name="org.ofbiz.ofbizdemo" title="OfbizDemo Entity">
<field name="ofbizDemoId" type="id-ne"><description>primary sequenced ID</description></field>
<field name="ofbizDemoTypeId" type="id-ne"></field>
<field name="firstName" type="name"></field>
<field name="lastName" type="name"></field>
<field name="comments" type="comment"></field>
<prim-key field="ofbizDemoId"/>
<relation type="one" fk-name="ODEM_OD_TYPE_ID" rel-entity-name="OfbizDemoType">
<key-map field-name="ofbizDemoTypeId"/>
</relation>
</entity>
</entitymodel> |
Now have a look at $OFBIZ_HOME/hot-deploy/ofbizdemo/ofbiz-component.xml file. You already have resource entry made in it for loading these entities from their definitions to database when component loads. As shown below:
Code Block |
---|
|
<entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel.xml"/> |
To check simply re-start OFBiz (Ctrl+C followed by "./ant start") and direct your browser to Entity Data Maintenance Tool here: https://localhost:8443/webtools/control/entitymaint and search for entities OfbizDemoType and OfbizDemo. You will see it as shown in below given image.
...
In our previous section, we have seen how to create the entities (tables), now it's time to create a form which will allow you to make entries in that entity.
Create a Service
Before preparing form, let's write a service to create records in database for OfbizDemo entity in service definition xml file ($OFBIZ_HOME/hot-deploy/ofbizdemo/servicedef/services.xml)
Code Block |
---|
language | xml |
---|
title | services.xml |
---|
|
|
<?xml version="1.0" encoding="UTF-8"?> |
<
services
<services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/services.xsd"> |
<
description
>OfbizDemo Services</
description
>
<
vendor
></
vendor
>
<
version
>1.0</
version
>
<
service
<description>OfbizDemo Services</description>
<vendor></vendor>
<version>1.0</version>
<service name="createOfbizDemo" default-entity-name="OfbizDemo" engine="entity-auto" invoke="create" auth="true"> |
<
description
>Create an Ofbiz Demo record</
description
>
<
auto-attributes
<description>Create an Ofbiz Demo record</description>
<auto-attributes include="pk" mode="OUT" optional="false"/> |
<
auto
<auto-attributes include="nonpk" mode="IN" optional="false"/> |
<
override
<override name="comments" optional="true"/> |
</
service
>
</
services
>
Now again have a look at $OFBIZ_HOME/hot-deploy/ofbizdemo/ofbiz-component.xml file. You already have resource entry made in it for loading services defined in this file as:
Code Block |
---|
|
<!-- service resources: model(s), eca(s) and group definitions --> |
<
service
<service-resource type="model" loader="main" location="servicedef/services.xml"/> |
For this service definition to load you will need to restart OFBiz. To test this service you directly go to webtools --> Run Service option here: https://localhost:8443/webtools/control/runService
Info |
---|
Running service via Web Tools: This a smart utility provided by framework to run your service. On submission of the form above, you will presented a form to enter IN parameters of the service. |
Let's create our first form for this service and for that let's edit the existing file at location $OFBIZ_HOME/hot-deploy/ofbizdemo/widget/OfbizDemoForms.xml and add Create Form for OfbizDemo as shown below:
Code Block |
---|
language | xml |
---|
title | OfbizDemoForms.xml |
---|
|
|
<?xml version="1.0" encoding="UTF-8"?> |
<
forms
<forms xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/widget-form.xsd"> |
<
form
<form name="AddOfbizDemo" type="single" target="createOfbizDemo"> |
<!--We
have this utility in OFBiz to render form based on service definition.
Service attributes will automatically lookedup and will be shown on form
--> |
<
auto
<auto-fields-service service-name="createOfbizDemo"/> |
<
field
<field name="ofbizDemoTypeId" title="${uiLabelMap.CommonType}"> |
<
drop
<drop-down allow-empty="false" current-description=""> |
<!---We have made this drop down options dynamic(Values from db) using this --> |
<
entity-options
<entity-options description="${description}" key-field-name="ofbizDemoTypeId" entity-name="OfbizDemoType"> |
<
entity
<entity-order-by field-name="description"/> |
options>
down>
</
field
>
<
field
name
=
down>
</field>
<field name="submitButton" title="${uiLabelMap.CommonAdd}" |
><
submit
><submit button-type="button"/></ |
field
>
</
form
>
</
forms
>
Here you can notice we have used auto-fields-service to auto generate the form based on service definition IN/OUT attributes.
Go to Screens xml file(OfbizDemoScreens.xml) add this form location in decorator body to your screen that you used to show the Hello World... text. As shown below
Code Block |
---|
language | xml |
---|
title | Adding Form Location to the Main Screen |
---|
|
< <?xml version="1.0" encoding="UTF-8"?> |
<
screens
<screens xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/widget-screen.xsd"> |
<
screen
<
section
>
<
actions
>
<
set
field
=
"headerItem"
value
=
"main"
/>
</
actions
>
<
widgets
>
<
decorator-screen
<section>
<actions>
<set field="headerItem" value="main"/><!-- this highlights the selected menu-item with name "main" -->
</actions>
<widgets>
<decorator-screen name="main-decorator" location="${parameters.mainDecoratorLocation}"> |
<
decorator-section
name
=
"body"
>
<
screenlet
<decorator-section name="body">
<screenlet title="Add Ofbiz Demo"> |
<
include-form
<include-form name="AddOfbizDemo" location="component://ofbizdemo/widget/OfbizDemoForms.xml"/> |
</
screenlet
>
</
decorator-section
>
</
decorator-screen
>
</
widgets
>
</
section
>
</
screen
>
</
screens
>
</screenlet>
</decorator-section>
</decorator-screen>
</widgets>
</section>
</screen>
</screens> |
Controller Entry for Form
Before you go to the form and start creating OfbizDemo records from add form, you will need to make an entry in $OFBIZ_HOME/hot-deploy/ofbizdemo/webapp/ofbizdemo/WEB-INF/controller.xml file for the target service which will called when form is submitted. You can do it as shown below under Request Mappings in your ofbizdemo apps controller file:
<
request Code Block |
---|
|
<request-map uri="createOfbizDemo"> |
<
security
<security https="true" auth="true"/> |
<
event
<event type="service" invoke="createOfbizDemo"/> |
<
response
<response name="success" type="view" value="main"/> |
map>
Everything set, let's have a look into to our recently create form http://localhost:8080/ofbizdemo
Primary key(ofbizDemoId) is not needed to be send in with the form, it will be auto sequenced by OFBiz in db records.
Let's create a find form for the entity OfbizDemo, so that you search OfbizDemos being created.
1.) Add the forms (FindOfbizDemo and ListOfbizDemo) in OfbizDemoForms.xml
Code Block |
---|
language | xml |
---|
title | OfbizDemoForms.xml |
---|
|
<
form
<form name="FindOfbizDemo" type="single" target="FindOfbizDemo" default-entity-name="OfbizDemo"> |
<
field
<field name="noConditionFind" |
><
hidden
><><!-- if this isn't there then with all fields empty no query will be done -- |
></
field
>
<
field
></field>
<field name="ofbizDemoId" title="${uiLabelMap.OfbizDemoId}" |
><
textfield
>
<
field
field>
<field name="firstName" title="${uiLabelMap.OfbizDemoFirstName}" |
><
textfield
>
<
field
field>
<field name="lastName" title="${uiLabelMap.OfbizDemoLastName}" |
><
textfield
>
<
field
field>
<field name="ofbizDemoTypeId" title="${uiLabelMap.OfbizDemoType}"> |
<
drop
<drop-down allow-empty="true" current-description=""> |
<
entity
<entity-options description="${description}" key-field-name="ofbizDemoTypeId" entity-name="OfbizDemoType"> |
<
entity
<entity-order-by field-name="description"/> |
options>
down>
</
field
>
<
field
down>
</field>
<field name="searchButton" title="${uiLabelMap.CommonFind}" widget-style="smallSubmit" |
><
submit
><submit button-type="button" image-location="/images/icons/magnifier.png"/></ |
field
>
</
form
>
<
form
field>
</form>
<form name="ListOfbizDemo" type="list" list-name="listIt" paginate-target="FindOfbizDemo" default-entity-name="OfbizDemo" separate-columns="true" |
odd-row-style="alternate-row" header-row-style="header-row-2" default-table-style="basic-table hover-bar"> |
<
actions
>
<actions>
<!--Preparing
search results for user query by using OFBiz stock service to perform
find operations on a single entity or view entity --> |
<
service
<service service-name="performFind" result-map="result" result-map-list="listIt"> |
<
field
<field-map field-name="inputFields" from-field="ofbizDemoCtx"/> |
<
field
<field-map field-name="entityName" value="OfbizDemo"/> |
<
field
<field-map field-name="orderBy" from-field="parameters.sortField"/> |
<
field
<field-map field-name="viewIndex" from-field="viewIndex"/> |
<
field
<field-map field-name="viewSize" from-field="viewSize"/> |
</
service
>
</
actions
>
<
field
</service>
</actions>
<field name="ofbizDemoId" title="${uiLabelMap.OfbizDemoId}" |
><
display
field
>
<
field
field>
<field name="ofbizDemoTypeId" title="${uiLabelMap.OfbizDemoType}" |
><
display><display-entity entity-name="OfbizDemoType"/></ |
field
>
<
field
field>
<field name="firstName" title="${uiLabelMap.OfbizDemoFirstName}" sort-field="true" |
><
display
field
>
<
field
field>
<field name="lastName" title="${uiLabelMap.OfbizDemoLastName}" sort-field="true" |
><
display
field
>
<
field
field>
<field name="comments" title="${uiLabelMap.OfbizDemoComment}" |
><
display
field
>
form
>
Form or Screen's action tag is used for data preparation logics for your view.
Image Removed Info |
---|
We have used OOTB OFBiz generic service performFind to do the search operations which is easy and efficient to use when you have to perform search on one entity or one view entity. |
2.) In next step, we will include these form in the screen, let's add these form in OfbizDemoScreens.xml file. For this include the FindOfbizDemo screen defined below in the OfbizDemoScreens.xml
< Code Block |
---|
|
<!-- Find and list all ofbizdemos in a tabular format --> |
<
screen
<screen name="FindOfbizDemo"> |
<
section
>
<
actions
>
<
set
field
<section>
<actions>
<set field="headerItem" value="findOfbizDemo"/> |
<
set
<set field="titleProperty" value="PageTitleFindOfbizDemo"/> |
<
set
<set field="ofbizDemoCtx" from-field="parameters"/> |
</
actions
>
<
widgets
>
<
decorator-screen
</actions>
<widgets>
<decorator-screen name="main-decorator" location="${parameters.mainDecoratorLocation}"> |
<
decorator-section
name
=
"body"
>
<
section
>
<
condition
>
<
if-has-permission
<decorator-section name="body">
<section>
<condition>
<if-has-permission permission="OFBIZDEMO" action="_VIEW"/> |
</
condition
>
<
widgets
>
<
decorator-screen
</condition>
<widgets>
<decorator-screen name="FindScreenDecorator" location="component://common/widget/CommonScreens.xml"> |
<
decorator-section
<decorator-section name="search-options"> |
<
include-form
<include-form name="FindOfbizDemo" location="component://ofbizdemo/widget/OfbizDemoForms.xml"/> |
</
decorator-section
>
<
decorator-section
</decorator-section>
<decorator-section name="search-results"> |
<
include-form
<include-form name="ListOfbizDemo" location="component://ofbizdemo/widget/OfbizDemoForms.xml"/> |
</
decorator-section
>
</
decorator-screen
>
</
widgets
>
<
fail-widgets
>
<
label
</decorator-section>
</decorator-screen>
</widgets>
<fail-widgets>
<label style="h3">${uiLabelMap.OfbizDemoViewPermissionError}< |
/label
>
</
fail-widgets
>
</
section
>
</
decorator-section
>
</
decorator-screen
>
</
widgets
>
</
section
>
</
screen
>
/label>
</fail-widgets>
</section>
</decorator-section>
</decorator-screen>
</widgets>
</section>
</screen> |
3.) Add request mapping for accessing this new Find Ofbiz Demo page in controller.xml
Code Block |
---|
|
<!-- Request Mapping --> |
<
request
<request-map uri="FindOfbizDemo" |
><
security
><security https="true" auth="true"/ |
><response
><response name="success" type="view" value="FindOfbizDemo"/></request- |
map>
map>
<!-- View Mapping --> |
<
view
<view-map name="FindOfbizDemo" type="screen" page="component://ofbizdemo/widget/OfbizDemoScreens.xml#FindOfbizDemo"/> |
4.) Now, let's add a new menu for showing find option.
Creating a menu is really simple in OFBiz, all the menus are defined is *menus.xml.
When we create a component from ant target, we get a file named OfbizDemoMenus.xml
Make the following entry in the OfbizDemoMenus.xml file.
Code Block |
---|
language | xml |
---|
title | OfbizDemoMenus.xml |
---|
|
<?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="${uiLabelMap.OfbizDemoApplication}" extends="CommonAppBarMenu" extends-resource="component://common/widget/CommonMenus.xml">
<menu-item name="main" title="${uiLabelMap.CommonMain}"><link target="main"/></menu-item>
<menu-item name="findOfbizDemo" title="${uiLabelMap.OfbizDemoFind}"><link target="FindOfbizDemo"/></menu-item>
</menu>
</menus> |
Use of UI Labels
Internationalization of Apache OFBiz is really easy, we define the UI Labels in various languages and on the basis of user's locale, respective label is shown.
Here is the example of UI Labels (while creating component <component-name>UiLabels.xml is created by default, in our case it is OfbizDemoUiLabels.xml)
Code Block |
---|
language | xml |
---|
title | OfbizDemoUiLabels.xml |
---|
|
<
property
<property key="OfbizDemoFind"> |
<
value
<value xml:lang="en">Find</ |
value
>
</
property
>
<
property
value>
</property>
<property key="OfbizDemoFirstName"> |
<
value
<value xml:lang="en">First Name</ |
value
>
</
property
>
<
property
value>
</property>
<property key="OfbizDemoId"> |
<
value
<value xml:lang="en">OFBiz Demo Id</ |
value
>
</
property
>
<
property
value>
</property>
<property key="OfbizDemoLastName"> |
<
value
<value xml:lang="en">Last Name</ |
value
>
property
>
Services using other engines
Whenever you have to build a business logic you should prefer to write services to leverage features from its built in Service Engine.
The service "createOfbizDemo" that you created earlier was using engine="entity-auto" and hence you didn't need to provide its implementation and OFBiz took care of create operation. When you need to work on complex operations in service involving multiple entities from database and custom logics to be built, you need to provide custom implementation to your service. In this section we will focus on this.
Service in Java
You can implement a service in Java as directed here in below given steps:
1.) Define your service, here again we will be operating on the same entity(OfbizDemo) of our custom Ofbiz Demo application. Open your service definition file $OFBIZ_HOME/hot-deploy/ofbizdemo/servicedef/services.xml and add a new definition as:
<
service
Code Block |
---|
language | xml |
---|
title | services.xml |
---|
|
<service name="createOfbizDemoByJavaService" default-entity-name="OfbizDemo" engine="java" |
location="com.companyname.ofbizdemo.services.OfbizDemoServices" invoke="createOfbizDemo" auth="true"> |
<
description
>Create an Ofbiz Demo record using a service in Java</
description
>
<
auto-attributes
<description>Create an Ofbiz Demo record using a service in Java</description>
<auto-attributes include="pk" mode="OUT" optional="false"/> |
<
auto
<auto-attributes include="nonpk" mode="IN" optional="false"/> |
<
override
<override name="comments" optional="true"/> |
service
>
Image Removed |
---|
Notice we have this time used engine="java". |
2.) Create package in your ofbizdemo components src directory e.g. src --> com --> companyname --> ofbizdemo --> services. Services which has to be implemented in Java can be placed in this directory for your application.
3.) Define new Java Class in file OfbizDemoServices.java here in services directory and implement method, which is going to be invoked by your service definition, as shown below:
OfbizDemoServices.java
package src.com.companyname.ofbizdemo.services; import java.util.Map;
import org.ofbiz.base.util.Debug;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.service.DispatchContext;
import org.ofbiz.service.ServiceUtil;
public class OfbizDemoServices {
public static final String module = OfbizDemoServices. class .getName();
public static Map<String, Object> createOfbizDemo(DispatchContext dctx, Map<String, ? extends Object> context) {
Map<String, Object> result = ServiceUtil.returnSuccess();
Delegator delegator = dctx.getDelegator();
try {
GenericValue ofbizDemo = delegator.makeValue( "OfbizDemo" );
ofbizDemo.setNextSeqId();
ofbizDemo.setNonPKFields(context);
ofbizDemo = delegator.create(ofbizDemo);
result.put( "ofbizDemoId" , ofbizDemo.getString( "ofbizDemoId" ));
Debug.log( "==========This is my first Java Service implementation in Apache OFBiz. OfbizDemo record created successfully with ofbizDemoId: " +ofbizDemo.getString( "ofbizDemoId" ));
} catch (GenericEntityException e) {
Debug.logError(e, module);
return ServiceUtil.returnError( "Error in creating record in OfbizDemo entity ........" +module);
}
return result;
}
}
|
4.) Stop server and re-start using "./ant clean build start", it will compile your class and will make it available when ofbiz restarts which updated jar file.
5.) Test service implemented using webtools --> Run Service option(https://localhost:8443/webtools/control/runService) or simply update the service name being called by your controller request to use this service instead and use add form in your app that you prepared earlier. By doing this your Add OfbizDemo form will call this java service.
< request-map uri = "createOfbizDemo" >
< security https = "true" auth = "true" />
< event type = "service" invoke = "createOfbizDemoByJavaService" />
< response name = "success" type = "view" value = "main" />
</ request-map >
|
To make sure this new service implementation is being executed, you can check this line in console log that you have put in your code using Debug.log(....). For logging in OFBiz you must always use Debug class methods in Java classes.
Console Log
[java] 2014 - 06 - 24 12 : 11 : 37 , 282 (http-bio- 0.0 . 0.0 - 8443 -exec- 2 ) [ OfbizDemoServices.java: 28 :INFO ] ==========This is my first Java Service implementation in Apache OFBiz. OfbizDemo record created successfully with ofbizDemoId: ......
|
Service in Groovy
To utilize feature of on the fly compilation and less line of code you can implement services for building business logics in OFBiz using Groovy DSL.
To implement a service using Groovy you can follow below given steps:
1.) Add new service definition to services/services.xml file as:
services.xml
< service name = "createOfbizDemoByGroovyService" default-entity-name = "OfbizDemo" engine = "groovy"
< description >Create an Ofbiz Demo record using a service in Java</ description >
< auto-attributes include = "pk" mode = "OUT" optional = "false" />
< auto-attributes include = "nonpk" mode = "IN" optional = "false" />
< override name = "comments" optional = "true" />
</ service >
|
2.) Add new groovy services file here component://ofbizdemo/script/com/companyname/ofbizdemo/OfbizDemoServices.groovy
3.) Add service implementation to the file OfbizDemoServices.groovy
OfbizDemoServices.groovy
def createOfbizDemo() {
result = [:];
try {
ofbizDemo = delegator.makeValue( "OfbizDemo" );
ofbizDemo.setNextSeqId();
ofbizDemo.setNonPKFields(context);
ofbizDemo = delegator.create(ofbizDemo);
result.ofbizDemoId = ofbizDemo.ofbizDemoId;
logInfo( "==========This is my first Groovy Service implementation in Apache OFBiz. OfbizDemo record "
+ "created successfully with ofbizDemoId: " +ofbizDemo.getString( "ofbizDemoId" ));
} catch (GenericEntityException e) {
logError(e.getMessage());
return error( "Error in creating record in OfbizDemo entity ........" );
}
return result;
}
|
4.) Stop server and re-start using ./ant start, this time we just need to load the new service definition, no explicit compilation is required as its a service implementation in Groovy.
5.) Test service implemented using webtools --> Run Service option(https://localhost:8443/webtools/control/runService) or simply update the service name being called by your controller request to use this service instead and use add form in your app that you prepared earlier for testing. By doing this your Add OfbizDemo form will call this groovy service.
controller.xml
< request-map uri = "createOfbizDemo" >
< security https = "true" auth = "true" />
< event type = "service" invoke = "createOfbizDemoByGroovyService" />
< response name = "success" type = "view" value = "main" />
</ request-map >
|
To make sure this new service implementation is being executed, you can check this line in console log that you have put in your code using Debug.log(....). For logging in OFBiz you must always use Debug class methods in Java classes.
[java] 2014 - 06 - 24 12 : 11 : 37 , 282 (http-bio- 0.0 . 0.0 - 8443 -exec- 2 ) [ OfbizDemoServices.java: 28 :INFO ] ==========This is my first Groovy Service implementation in Apache OFBiz. OfbizDemo record created successfully with ofbizDemoId: .....
|
To get more details around using Groovy DSL for service and events implementation in Apache OFBiz you can refer document created by Jacopo Cappellato in OFBiz Wiki here.
...