BLOG

NEXT STEPS

Posts Tagged ‘OFBiz Tutorial’

OFBiz Tutorial – Implementing a Product CSV export

Thursday, February 11th, 2010

At the end of the last post in our OFBiz tutorial series we have completed the final version of a simple product list screen completely based on OFBiz widgets.

Here is the screen definition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<screen name="ProductList">
    <section>
        <actions>
            <entity-condition entity-name="Product" list="products">
                <order-by field-name="productId"/>
            </entity-condition>
        </actions>
        <widgets>
            <decorator-screen name="HwmCommonDecorator" location="component://hwm/widget/CommonScreens.xml">
                <decorator-section name="body">
                    <label text="Finished Products" style="h1"/>
                    <include-form name="ListProducts" location="component://hwm/widget/HwmForms.xml"/>
                </decorator-section>
            </decorator-screen>
        </widgets>
    </section>
</screen>

and the form definition:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<form name="ListProducts" type="list" list-name="products">
    <row-actions>
        <service service-name="getProductInventoryAvailable" result-map="inventoryAvailableMap">
            <field-map field-name="productId" from-field="productId"/>
        </service>
    </row-actions>
    <field name="productId" widget-style="buttontext">
        <hyperlink target="/catalog/control/EditProduct" description="${productId}" target-type="inter-app">
            <parameter param-name="productId"/>
        </hyperlink>
    </field>
    <field name="productTypeId" title="Product Type">
        <display-entity entity-name="ProductType"/>
    </field>
    <field name="internalName"><display/></field>
    <field name="description"><display/></field>
    <field name="qoh" entry-name="inventoryAvailableMap.quantityOnHandTotal">
        <display/>
    </field>
    <field name="atp" entry-name="inventoryAvailableMap.availableToPromiseTotal">
        <display/>
    </field>
</form>

and the end result is this:
The final result

Our next goal, the subject of this post, is to provide a CSV (Comma Separated Value) export of the same list of products; we will do this by reusing as much as possible the artifacts already implemented for the html screen.

A CSV file is a widely used simple format for the exchange of data between different software systems; for example, Microsoft Excel can easily import a CSV file into a spreadsheet. From a technical point of view a CSV file is a plain text file where each line represents a row from a list of homogeneous data, and the fields are separated by the comma character.
CSV exports are supported out of the box by the OFBiz widgets.
In this excercise we will:

  1. add to the product list screen a link that will generate the CSV export
  2. add to the controller.xml file the request and view entries for the new CSV export screen
  3. implement the new screen definition for the CSV export screen; the screen will reuse the same form used by html screen

Adding a link element

We will add a link from the product list screen to invoke the product CSV export screen. The definition of a link element in a screen is easy:

1
2
3
<container style="button-bar">
    <link target="ProductListExport" text="CSV Export" style="buttontext"/>
</container>
  • the “container” element is not mandatory but we have used it in order to create an invisible region of the screen for the links (we will add a new link in our next post, for PDF exports)
  • the link element is defined in the same way we have defined the link field in the product list form in our last post

Controller entries for a CSV export screen

1
2
3
4
5
6
<request-map uri="ProductListExport">
    <security https="true" auth="true"/>
    <response name="success" type="view" value="ProductListExportScreen"/>
</request-map>
...
<view-map name="ProductListExportScreen" type="screencsv" content-type="text/csv" page="component://hwm/widget/HwmScreens.xml#ProductListExport"/>

The entries are very similar to the ones we have implemented in a previous post for the product list screen. There are just a couple of things to notice:

  • the request-map uri must match with the target of the link element in the screen (”ProductListExport”)
  • in the view-map, the type is now “screencsv” (instead of “screen”) because we have to invoke the “csv screen renderer”
  • in the view-map we have also set the content-type to “text/csv” as useful metadata information for the browser

Screen definition for CSV export screens

There isn’t anything special in a screen definition for a CSV export; the screen is defined in the same way of a normal screen, except for a couple of details:

1
2
3
4
5
6
7
8
9
10
11
12
13
<screen name="ProductListExport">
    <section>
        <actions>
            <set field="viewSize" value="10000"/>
            <entity-condition entity-name="Product" list="products">
                <order-by field-name="productId"/>
            </entity-condition>
        </actions>
        <widgets>
            <include-form name="ListProducts" location="component://hwm/widget/HwmForms.xml"/>
        </widgets>
    </section>
</screen>
  • the screen definition is mostly identical to the “product list screen”
  • in particular, the entity-condition element is the same and it is used to select the list of products for the export
  • the form that is included is the same of the “product list screen”: we will not have to re-implement it because the widget renderer will take care of rendering it into the proper output (CSV or html)
  • the “set” field operation, where we set “viewSize” to “10000″, is an easy way to “disable” pagination; we actually define the top limit of our product export to 10000 records here, but of course we can use a different value

Conclusion

The exercise is complete and we can test the product export by clicking the “CSV Export” link (there is no need to restart OFBiz).

Implementing the CSV export ended up being a trivial task because, thanks to the OFBiz widgets, we have reused most of the work we did for the html screen.

In the next tutorial post we will perform similar steps to implement the PDF version of the same screen.

- Jacopo

Jacopo Cappellato is VP of Technology at HotWax Media and has been involved with the OFBiz project since 2003. He is an OFBiz Project Committer and a member of both the OFBiz Project Management Committee and the Apache Software Foundation.

Jacopo Cappellato - OFBiz Developer - OFBiz Expert

OFBiz Tutorial – Enhancing the Product list screen

Wednesday, January 27th, 2010

As you become an expert OFBiz developer, you will certainly need to know all about the OFBiz Form Widget! Here at HotWax Media we use the Form Widget regularly, whether as part of a front end e-commerce shopping cart or as part of a back-end ERP administration screen (for example OFBiz screens to handle order management, warehouse management, and inventory management as part of your integrated online retail OFBiz system).

In this post we will explore some of the features offered by the form widget, the layer in the OFBiz framework that enables the implementation of list based user interface elements. We will do this by continuing the exercise we started in our earlier “OFBiz Tutorial” posts. Specifically, this exercise is based on the “hwm” component we have setup in OFBiz Tutorial – Custom Components In OFBiz and on the custom “product list” screen we have built in OFBiz Tutorial – Building A Simple Product List Screen Here is the form widget definition for the list of products that we have created in the last post:

1
2
3
<form name="ListProducts" type="list" list-name="products">
    <auto-fields-entity entity-name="Product" default-field-type="display"/> 
</form>

The auto-fields element was all we needed to retrieve the fields defined in the “Product” entity (entity-name) and render them as “display” fields (default-field-type). The goal of this post is to fine tune the list definition, in order to render only a subset of the fields and also to render them in a richer way; specifically:

  • we want to render the “product id” field as a link to the “product detail screen” in the OFBiz “Catalog” application

  • instead of displaying the id in the “product type id” field, we want to display the description associated to that id
  • we are only interested in the following fields from the “Product” entity: “product id” (as a link), “product type id” (as a description), “internal name”, “description”
  • we want to add two computed fields containing the “quantity on hand” and “available to promise” quantity of the items in inventory

Defining links

In order to transform the “product id” field into a link, we will simply add the field definition right after the “auto-fields” element; in this way, the explicit field type (link) will override the field type defined by the “default-field-type” attribute; here is the updated field definition:

1
2
3
4
5
6
7
8
<form name="ListProducts" type="list" list-name="products">
    <auto-fields-entity entity-name="Product" default-field-type="display"/> 
    <field name="productId" widget-style="buttontext">
        <hyperlink target="/catalog/control/EditProduct" target-type="inter-app" description="${productId}"> 
            <parameter param-name="productId"/> 
        </hyperlink> 
    </field> 
</form>

When you refresh the screen you will immediately see the new form definition in action. Here are some details about the new field definition:

  • the attribute widget-style=”buttontext” sets the style for the field by using one of the many styles available in OFBiz (and defined in a shared CSS stylesheet; you can of course define and use your own styles)

  • the “description” attribute in the “hyperlink” element defines the text rendered as hyperlink; we have used the ${} notation to insert the “productId” variable
  • the “target” attribute in the “hyperlink” element defines the url for the hyperlink; this url is defined in the controller.xml file of the corresponding “catalog” web application (defined in the applications/product component); since the link, from the “hwm” application, points to a different application we use the target-type=”inter-app” attribute
  • the “description” attribute in the “hyperlink” element defines the text rendered as hyperlink; we have used the ${} notation to insert there the “productId” variable
  • the “parameter” element is needed because the EditProduct url requires that a productId parameter is passed to it

Performing lookups to different entities

Instead of displaying the id for the product type, as stored in the Product.productTypeId field, we prefer to display the description associated to that type; for example, instead of “FINISHED_GOOD” we want “Finished Good”. The description is not stored in the Product entity, it is instead in the ProductType entity: we have to use the Product.productTypeId field to perform a table lookup in the ProductType entity (Product.productTypeId = ProductType.productTypeId), and use the content of the ProductType.description field when the form is rendered. The form widget has built-in support for this, the “display-entity” element:

1
2
3
<field name="productTypeId" title="Product Type">
    <display-entity entity-name="ProductType"/>
</field>

When you refresh the screen you will immediately see the new form definition in action. Here are some details about the new field definition:

  • the “entity-name” defines the entity to lookup

  • this is all we have to specify here, because, if not specified, OFBiz assumes that the name of the field (name=”productTypeId”) is the same in both entities and assumes that a “description” field is available in the referenced entity; if the id and description fields in the referenced entity have different names, you can specify them by adding the “description” and “key-field-name” attributes to the “display-entity” element

Displaying just the fields we need

We now realize that we don’t need most of the fields of the “Product” entity; for this reason it is easier to remove the “auto-fields” element and simply add the field definition for the two more fields we want to display (”internal name” and “description”). Here is the new form definition:

1
2
3
4
5
6
7
8
9
10
11
12
<form name="ListProducts" type="list" list-name="products">
    <field name="productId" widget-style="buttontext"> 
        <hyperlink target="/catalog/control/EditProduct" description="${productId}" target-type="inter-app">
            <parameter param-name="productId"/>
        </hyperlink>
    </field>
    <field name="productTypeId" title="Product Type">
        <display-entity entity-name="ProductType"/>
    </field> 
    <field name="internalName"><display/></field>
    <field name="description"><display/></field>
</form>

Displaying fields computed by services

This is the most interesting part of this exercise. We want to add two additional fields to the list: one with the count of units physically in the warehouse for the product, and one with the units available in warehouse for sales (i.e. units not reserved by sales orders). This information is not stored in the Product or other entities, and computing the units is not an easy task, because, in order to enable multi warehouse support, material tracking and quality control, the OFBiz data model for inventory is rather complex. However there is a standard service (a reusable business logic) specifically designed to count inventory: the “getProductInventoryAvailable” service. In its simplest form the service takes as input a productId and returns as output a map containing two fields, “quantityOnHandTotal” and “availableToPromiseTotal”; this is exactly what we need. But we have to call this service for each record in the list, get the result from the service and use it to populate the two new columns. Again, the form widget assists us with built-in support for service calls, using the “row-actions” and “service” elements:

1
2
3
4
5
6
7
8
9
 
<form name="ListProducts" type="list" list-name="products">
    <row-actions> 
        <service service-name="getProductInventoryAvailable" result-map="inventoryAvailableMap">
            <field-map field-name="productId" from-field="productId"/>
        </service>
    </row-actions> 
... 
</form>
  • all the actions inside the “row-actions” section are executed before each row is rendered; this tag is similar to the “actions” tag that we have used in a previous post, with the only difference that “actions” is executed once before the list is rendered, while “row-actions” is executed before each and every row in the list; a form definition can also contain both action elements
  • the “service” action is a convenient way to invoke a service: the service name is specified with the “service-name” attribute, the “field-map” elements are used to pass the input parameters to the service, the “result-map” attribute defines the name of the output map

We can now add the two new computed fields in the following way:

1
2
3
4
5
6
<field name="qoh" entry-name="inventoryAvailableMap.quantityOnHandTotal"> 
    <display/>
</field> 
<field name="atp" entry-name="inventoryAvailableMap.availableToPromiseTotal">
    <display/>
</field>

the “entry-name” attribute is used to explicitly specify the source of the content: the service result map that we have named “inventoryAvailableMap”, and the “quantityOnHandTotal” and “availableToPromiseTotal” fields.

Conclusion

Here is the final result of our programming efforts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<form name="ListProducts" type="list" list-name="products">
    <row-actions>
        <service service-name="getProductInventoryAvailable" result-map="inventoryAvailableMap">
            <field-map field-name="productId" from-field="productId"/>
        </service>
    </row-actions>
    <field name="productId" widget-style="buttontext">
        <hyperlink target="/catalog/control/EditProduct" description="${productId}" target-type="inter-app">
            <parameter param-name="productId"/>
        </hyperlink>
    </field>
    <field name="productTypeId" title="Product Type">
        <display-entity entity-name="ProductType"/>
    </field>
    <field name="internalName"><display/></field>
    <field name="description"><display/></field>
    <field name="qoh" entry-name="inventoryAvailableMap.quantityOnHandTotal">
        <display/>
    </field>
    <field name="atp" entry-name="inventoryAvailableMap.availableToPromiseTotal">
        <display/>
    </field>
</form>

and here is how the list is rendered:

The final result

Our form is now completed and in the next post we will reuse it to build a CSV (Comma Separated Value) export.

- Jacopo

Jacopo Cappellato is VP of Technology at HotWax Media and has been involved with the OFBiz project since 2003. He is an OFBiz Project Committer and a member of both the OFBiz Project Management Committee and the Apache Software Foundation.

Jacopo Cappellato - OFBiz Developer - OFBiz Expert

OFBiz Tutorial – Building A Simple Product List Screen

Thursday, December 17th, 2009

In this post we will create our first simple html screen to print on screen all the products in our system.

This exercise is based on the “hwm” component we have setup in the last blog post OFBiz Tutorial – Custom Components In OFBiz: all the code we will implement will be contained in the custom component.

Here are the steps required to build the new screen:

  1. create a form definition for the list of products
  2. create a screen definition to include the form in a page
  3. create controller entries to associate the screen to a URL/address for the browser
  4. create a menu item to reach the new screen by clicking a link in a menu

All the steps we will do doesn’t require to compile/build OFBiz and can be done while OFBiz is running; in this way you will be able to test the effects of your experiments immediately.

Form widget definition for the list of products

A form widget definition is an xml representation of a list or single form.

In OFBiz, the main entity (aka database table) for storing product related information is named “Product”.

Here is the code to define a form of “list” type, together with the code to retrieve all the records from the Product entity and display them in a list based format:

The location of the file to edit

The location of the file to edit

1
2
3
4
5
6
7
8
    <form name="ListProducts" type="list">
        <actions>
            <entity-condition entity-name="Product">
                <order-by field-name="productId"/>
            </entity-condition>
        </actions>
        <auto-fields-entity entity-name="Product" default-field-type="display"/>
    </form>

Things to consider:

  • the type of this form is “list” because we want to render its content from a list in tabular format; the other main type for forms is “single” and it is used for rendering single forms (e.g. forms for data entry like “New Product”)
  • the commands under the “actions” section are executed just before the form is rendered; here we are using the “entity-condition” command to retrieve all the records from the “Product” entity sorted by “productId”
  • instead of specifying field by field all the fields to be rendered we have used the “auto-fields-entity” command; in this way all the fields from the Product entity are included as “display” (aka read only) fields

Screen widget definition for the list of products

A screen widget definition is an xml representation of a screen (page) in the application.

Here is the code to define a new screen that contains the form defined in the above step:

The location of the file to edit

The location of the file to edit

1
2
3
4
5
6
7
8
9
10
11
12
13
    <screen name="ProductList">
        <section>
            <actions>
            </actions>
            <widgets>
                <decorator-screen name="HwmCommonDecorator" location="component://hwm/widget/CommonScreens.xml">
                    <decorator-section name="body">
                        <include-form name="ListProducts" location="component://hwm/widget/HwmForms.xml"/>
                    </decorator-section>
                </decorator-screen>
            </widgets>
        </section>
    </screen>

Things to consider:

  • the action section of this screen is empty (we could safely remove the “actions” tags) because we have decided to run the data preparation (selection of all the records from the “Product” entity) in the form; both ways are fine: if the data retrieval logic is really tied to the form, it is a good idea to put it into the form’s action tag (reusing the same form in different screen will be just a matter of including the form in the screen definitions); if the data retrieval logic is dependent on the screen but you want to reuse the same form definition in more screens (for example one screen for different groups of products), then it is a good idea to implement it into the screen’s action tag, and then reuse the same form in all the screens; we will do this switch later in this post.
  • with the “decorator-screen” element we specify the name (”HwmCommonDecorator”) and location of a screen decorator: the screen decorator is used to decorate our screen with all the application menus, the header and footer that are shared by all the screens;
  • the screen specific content will go in the “body” section of the decorator, that is why we use the “decorator-section” element and add the screen specific content there; in this example, we have just added the form definition for the form created in the previous step
  • the path to the form widget definition is expressed in the format “component://<ofbiz component name>/<relative path to the form definition xml file>”; this format is widely used in ofbiz and it is useful because makes the system independent from the actual location of the ofbiz home folder and also enables the extension mechanism of OFBiz (we will talk about this in another post)

Controller entries – the url of our screen

Controller entries are needed to define the URL to reach the screen; for each screen you have to create two entries, a request-map and a view-map:

The location of the file to edit

The location of the file to edit

1
2
3
4
5
6
    <request-map uri="ProductList">
        <security https="true" auth="true"/>
        <response name="success" type="view" value="ProductListScreen"/>
    </request-map>
...
    <view-map name="ProductListScreen" type="screen" page="component://hwm/widget/HwmScreens.xml#ProductList"/>

Things to consider:

  • in the controller.xml file all the request-map entries must be listed before the view-map entries
  • the request-map defines the URL of the screen for the browser; the “uri” attribute (”ProductList”) is the last part of the URL; the “security” element tells OFBiz to publish the page using the https protocol (https=”true”) and to grant access only to authenticated users (auth=”true”) (and redirect to the user login screen if a user is not already logged in); the end result is that the complete URL for the page will be: http://localhost:8080/hwm/control/ProductList
  • the view-map entry associates the “response” value defined in the request-map to the screen definition we have created in the previous step
  • there are many good reasons for decoupling the request-map to the view-map and this will be clearer when we will talk about events associated to user activities (e.g. form submissions)

Testing our work

If you have followed all the steps above you are now ready to test your work; no need to compile or restart OFBiz, just enter the following URL in your browser: https://localhost:8080/hwm/control/ProductList

You should see a screen like this: (Click on image to zoom)

OFBiz Product List

Things to consider:

  • all the fields of the Product entity have been automatically used as columns for the form list; the field names have been used to generate the column’s titles; all this happened because of the element “auto-fields-entity” we have used in the form definition
  • the framework has automatically decorated the form with pagination elements
  • all the records from the Product entity are shown, sorted by productId

A few simple experiments

Again, you can do all these changes without restarting OFBiz: just do them and reload the page after each and every change, this is a great way to explore the different options available.

The products are now sorted by productId in ascending order; if we want to sort them in descending order we just have to add the “-” symbol as a prefix of the field name in the “order-by” element of the “entity-condition”:

1
2
3
        <entity-condition entity-name="Product">
            <order-by field-name="-productId"/>
        </entity-condition>

if we want to sort by productTypeId and then productId:

1
2
3
4
        <entity-condition entity-name="Product">
            <order-by field-name="productTypeId"/>
            <order-by field-name="productId"/>
        </entity-condition>

If we want instead to filter all the product of type “finished good” and sort the result by productId:

1
2
3
4
        <entity-condition entity-name="Product">
            <condition-expr field-name="productTypeId" value="FINISHED_GOOD"/>
            <order-by field-name="productId"/>
        </entity-condition>

We can now add a label to the screen to explain that these are all the “finished products” in the system; in order to do this you will add a “label” element to the screen definition (see line 8):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    <screen name="ProductList">
        <section>
            <actions>
            </actions>
            <widgets>
                <decorator-screen name="HwmCommonDecorator" location="component://hwm/widget/CommonScreens.xml">
                    <decorator-section name="body">
                        <label text="Finished Products" style="h1"/>
                        <include-form name="ListProducts" location="component://hwm/widget/HwmForms.xml"/>
                    </decorator-section>
                </decorator-screen>
            </widgets>
        </section>
    </screen>

Adding a menu item for the new screen

Instead of typing the URL of our screen in the browser we want to add a link to it from the top level menu of the “Hwm” application.

Here is the code to do this (new code at line 3):

hwm-menus

1
2
3
4
    <menu name="MainAppBar" title="${uiLabelMap.HwmApplication}" extends="CommonAppBarMenu" extends-resource="component://common/widget/CommonMenus.xml">
        <menu-item name="main" title="${uiLabelMap.CommonMain}"><link target="main"/></menu-item>
        <menu-item name="ProductList" title="Product List"><link target="ProductList"/></menu-item>
    </menu>

Things to consider:

  • the content of the “target” element must match the request-map name in the controller

Internationalization

In the last two paragraphs we have added two textual labels in English, one as a “label” element in the screen and the other as the “title” of the menu item. A better way of doing this, especially if you are interested in building internationalized applications that can be translated in many different languages, is to use the OFBiz i18n layer. In order to do this you have to add the following key in the component’s UiLabel file:

hwm-labels

1
2
3
4
    <property key="HwmProductList">
        <value xml:lang="en">Product List</value>
        <value xml:lang="it">Lista Prodotti</value>
    </property>

and then use the key instead of the hardcoded “Product List” string; for example for the menu item the code is:

1
        <menu-item name="ProductList" title="${uiLabelMap. HwmProductList}"><link target="ProductList"/></menu-item>

Moving the data preparation code from the form’s to the screen’s actions tag

We have mentioned before that the data preparation code can stay in the form’s actions section or in the screen’s actions section; in the first paragraph of this post we have implemented the code in the form; we now move it to the screen’s actions section:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    <screen name="ProductList">
        <section>
            <actions>
                <entity-condition entity-name="Product" list="products">
                    <order-by field-name="productId"/>
                </entity-condition>
            </actions>
            <widgets>
                <decorator-screen name="HwmCommonDecorator" location="component://hwm/widget/CommonScreens.xml">
                    <decorator-section name="body">
                        <label text="Finished Products" style="h1"/>
                        <include-form name="ListProducts" location="component://hwm/widget/HwmForms.xml"/>
                    </decorator-section>
                </decorator-screen>
            </widgets>
        </section>
    </screen>

The entity-condition code is exactly the same with the only difference that now we have specified the “list” attribute: this is important because it represents the name of the variable that will contain the list of products selected; this name must match the same list-name attribute in the form definition that is now:

1
2
3
4
5
    <form name="ListProducts" type="list" list-name="products">
        <actions>
        </actions>
        <auto-fields-entity entity-name="Product" default-field-type="display"/>
    </form>

The “actions” section in the form is now empty and can be safely removed.

Homework

Now that we have the data preparation code in the screen, we can more easily implement an additional screen, that reuses the same form definition to list all the products of type “raw material” (productTypeId=”RAW_MATERIAL”): the implementation of the new screen, new controller entries, menu item, ui labels is a useful exercise.

Next steps

In the next posts we will explore some of the features of form widgets (and we will enhance our product list form) and we will see how we can implement a PDF and CSV versions of the screen.

- Jacopo

Jacopo Cappellato is VP of Technology at HotWax Media and has been involved with the OFBiz project since 2003. He is an OFBiz Project Committer and a member of both the OFBiz Project Management Committee and the Apache Software Foundation.
Jacopo Cappellato - OFBiz Developer - OFBiz Expert

OFBiz Tutorial – Custom Components in OFBiz

Tuesday, December 1st, 2009

This is the first of a series of posts that will introduce hands-on OFBiz development: each post will focus on a simple exercise that will unveil some of the powerful features of OFBiz.

In this post we will simply setup our sandbox environment: a custom component/application named “hwm” that is deployed in OFBiz and will contain our exercises.

OFBiz components

OFBiz Components

At its bare minimum, an OFBiz component is a folder, containing a special xml file, named “ofbiz-component.xml”, that describes the resources loaded and required by the component.
OFBiz itself is made up of components:

  • framework components: lower level components that provide the technical layer and tools to the application components; the features provided by these components are typically the ones provided by any other development framework (data layer, business logic layer, transaction handling, data source pools, etc…)
  • application components: they are generic ERP applications that can be used as they are or extended/customized (product, order, party, manufacturing, accounting etc…); application components have access to the services and tools provided by the framework components and to the services published by other application components
  • special purpose components: similar to the application components, the are special purpose applications like ecommerce, Google Base integration, eBay integration etc…
  • hot-deploy components: this folder is empty and it is where you can place your custom components; custom components have access to, and can extend/override, the resources published by all the other components

Prerequisites

  • JDK 1.6 is properly installed and the JAVA_HOME environment variable is correctly set; you can download Java from java.sun.com
  • an svn client is installed in your system (needed to checkout the latest OFBiz sources); you can freely download an svn client from tigris.org

Setting up the sandbox

These are the simple steps to download and build OFBiz and your custom component:

  1. Download the OFBiz source files from the official OFBiz SVN Respository (this step can take some time and requires access to the Internet): “svn co http://svn.apache.org/repos/asf/ofbiz/trunk ofbiz”
  2. go to the newly created folder: “cd ofbiz”
  3. run the ant task to create a standard OFBiz component: “./ant create-component” (and answer the questions when prompted, see below for details)
  4. build OFBiz and load the demo data: “./ant run-install”
  5. run OFBiz: “./ant run”

In short, here are the commands you have to type in a shell:

1
2
3
4
5
6
7
8
9
10
svn co http://svn.apache.org/repos/asf/ofbiz/trunk ofbiz
cd ofbiz
./ant create-component
      Component name: hwm
      Component resource name: Hwm
      Webapp name: hwm
      Base permission: HWM
      Confirm: Y
./ant run-install
./ant run

Now OFBiz and your custom applications are up and running; just point your browser to: http://localhost:8080/hwm
Login into the custom “hwm” application with username “admin” and password “ofbiz”.

More about the “create-component” script

Even if you can of course manually create an hot-deploy component, running the ant task “create-component” is the preferred way of starting with a new hot-deploy component because it is quick and generates a component layout that follows all the OFBiz best practices, enabling you to use and extend the existing OFBiz goodies:

  • entities (the data model)
  • services (business logic)
  • widgets (user interface elements like screens, forms, menus)
  • security (authentication and authorization)
  • localization
  • tools
  • etc…

The main advantage of using this development strategy is that all your custom code will be separated from the official OFBiz code, drastically simplifying the task of keeping your custom application updated with the new OFBiz versions. You will still be able to extend/override/customize specific OFBiz entities, services, screens and of course add new ones, just writing code into your custom component.

For the most curious of you, here are some details about the meaning of the questions asked by the “create-component” script:

  • component name: this is the name of the component (and also of the folder that will contain it, created in the hot-deploy folder); following OFBiz’s naming conventions, it should be a single word all lowercased (e.g. hwm)
  • component resource name: it will be used as a prefix for resources; you can just use the component name, possibly using an upper case character for the first character in the words (e.g. Hwm)
  • webapp name: this is the name and uri of the application in which the ui for the new component will be implemented; following OFBiz’s naming conventions, it should be a single word all lowercased (e.g. hwm)
  • base permission: this is the prefix for base security permissions; following OFBiz’s naming conventions, it should be a single word all uppercased (e.g. HWM)

Based on the answers provided, the script will setup a new component in the “hot-deploy” folder, with the following layout:

The layout of the custom component "hwm"

The layout of the custom component "hwm"

You may already recognize how the information collected from the user by the script has been used to generate the component.

Exploring the component layout

Now we have everything we need to start to practice with the development based on the OFBiz framework. In the upcoming posts we will use this component to perform some exercises that will help us to better understand how OFBiz works and how to use it to build powerful erp applications.

- Jacopo

Jacopo Cappellato is VP of Technology at HotWax Media and has been involved with the OFBiz project since 2003. He is an OFBiz Project Committer and a member of both the OFBiz Project Management Committee and the Apache Software Foundation.
Jacopo Cappellato - OFBiz Developer - OFBiz Expert

OFBiz Tutorial – Introduction to OFBiz Widgets

Friday, November 13th, 2009

OFBiz is a broadly-scoped, powerful tool for open source ERP and e-commerce.  Whether your project is a simple e-commerce shopping cart or a complex ERP implementation that includes custom order management, multi-channel integrations, and accounting, ease-of-use for the developers implementing your system translates directly to your bottom line.

The following OFBiz tutorial is technical in nature.  If you are a developer, enjoy!  If you are a manager, suggest that your developers have a look.  The OFBiz Widget goes a long way in saving you time — and money — in your open source e-commerce and ERP projects.

And remember: HotWax Media provides a complete set of OFBiz services, from business analysis through system design, UI design, and complete implementation.  So feel free to contact us today and leave the heavy lifting to us!

The OFBiz Widget is one of the core components of the OFBiz framework, its main goal is the definition and rendering of the OFBiz user interfaces.

Each widget represents a reusable user interface element, that can be included and extended by different applications.

The widgets allow to define, using a simple xml language, user interfaces elements like screen, menus, forms, trees in a platform and output independent format; the widgets are also tightly integrated with other key components of the OFBiz framework, like the “content”, “service” and “entity” engines, so that data preparation logic programming is greatly simplified and consistent with the rest of the framework.

At runtime, when a widget is to be rendered, its widget definition (in xml) is passed to the proper widget renderer that transforms it in the right output format: an html document, a PDF document, a comma separated value file etc…

Various renderers are available in OFBiz including the html, pdf, xml, text and now the csv renderer. The html renderer is widely used to render each and every screen of the applications, the pdf renderer is used for PDF documents, bar codes and PDF email attachments, the xml renderer is used to generate Microsoft Excel compliant xml exports, the csv is for exporting comma separated values files.

In the past, each renderer was implemented by a complex set of Java classes and the output code was embedded in its methods; this layout had some relevant cons: the code was difficult to maintain and customize because html/xml/xsl-fo code was embedded in Java methods, building new renderers was a complex task.

As a consequence very few OFBiz  committers were able to fix and enhance the widget code in the framework and the html layout of the output was not very good because web designers had a hard time dealing with the html code embedded in Java classes.

For these reasons, recently, all the complex, difficult to maintain and customize code of the renderers in OFBiz has been refactored by HotWax Media, by introducing the concept of a generic Macro Widget Renderer: a unified renderer that delegates the actual implementation of the output to a set of Freemarker macro calls. Now all the output depended code is in easy to modify/extend/customize Freemarker templates: web designers can edit the templates for a given output and see the results real time without the need to recompile or even restart the OFBiz instance. It is also incredibly easy to implement new special purpose renderers, to get new types of output/export for the widgets: in fact we expect that in the future the set of output formats available for the widgets will grow.

The CSV renderer is a good example of the new breed of lightweight renderers: it took few hours to implement and with it now virtually any widget form that represents tabular data can be exported in CSV format.

In short, here are the few steps we followed to implement the new CSV output:

  1. add to framework/widget/config/widget.properties a new section for the renderer
      ?View Code LANGUAGE
      1
      2
      3
      4
      5
      6
      7
      8
      
      # csv output
      screencsv.name=csv
      screencsv.screenrenderer=component://widget/templates/csvScreenMacroLibrary.ftl
      screencsv.formrenderer=component://widget/templates/csvFormMacroLibrary.ftl
      screencsv.menurenderer=component://widget/templates/csvMenuMacroLibrary.ftl
      screencsv.treerenderer=component://widget/templates/csvTreeMacroLibrary.ftl
      screencsv.default.contenttype=UTF-8
      screencsv.default.encoding=none
  2. implement the Freemarker macros for the new renderer by copying and modifying the ones of an existing renderer in framework/widget/templates: csvScreenMacroLibrary.ftl, csvFormMacroLibrary.ftl,csvMenuMacroLibrary.ftl, csvTreeMacroLibrary.ftl
  3. add a new entry for the renderer in framework/common/webcommon/WEB-INF/common-controller.xml
      <handler name=”screencsv” type=”view” class=”org.ofbiz.widget.screen.MacroScreenViewHandler”/>

After this you are ready to use the new renderer by associating, in a controller.xml file, the screen definition with the renderer:

?View Code LANGUAGE
1
2
3
view-map name="IncomeStatementListCsv" type="screencsv"
page="component://accounting/widget/ReportFinancialSummaryScreens.xml#IncomeStatementListCsv"
content-type="text/csv" encoding="none"
In one of my next posts we will illustrate an example of how the same form can be used to render html code and csv data.
- Jacopo
Jacopo Cappellato is VP of Technology at HotWax Media and has been involved with the OFBiz project since 2003.  He is an OFBiz Project Committer and a member of both the OFBiz Project Management Committee and the Apache Software Foundation.
Jacopo Cappellato - OFBiz Developer