Open Source Strategies
 
Main
About
Learn More
Services
Projects
Jobs
Contact

SourceForge.net Logo

Building a Complete Application with OFBiz

IMPORTANT: Please read about the recent changes before attempting this tutorial.

In this third tutorial, we will build a complete application with OFBiz. Our application will allow users to sign in and create an entry about themselves, their various hobbies, and see other people who have visited the site and their hobbies and comments as well. It is a simple guest book website.

Please be sure that you have read all the previous tutorials, as I will not repeat the same information here.

Defining the Data Model

The first step is to define the data model. We want to track persons and their hobbies and lookup all the hobbies of a person (or, alternatively, all the people who share a hobby.) The data model thus calls for person, hobby, and person-hobby linkage.

With a relational database, you would define two tables, one for a person and one for a hobby, and link them together with a third table. The third table would allow you to associate as many hobbies as you would want with a person, and vice versa. You would define foreign-keys to constrain the third table so only actual persons and hobbies are present.

OFBiz works similarly. You would define two entities, which we will call HelloPerson and HelloHobby, and a linking entity, HelloPersonHobby, and establish a relationships between them. The relationships serve as foreign-key constraints but also allow you to go from one entity to another without having to remember yourself what their respective keys are (or change your code when keys change.)

NOTE: We are creating an application with completely self-contained data model here for illustration. If we were building a real application, the best practice would be to reuse as many existing OFBiz entities as possible, so instead of creating our own HelloPerson, we would be using the existing OFBiz Party/Person/PartyGroup entities.

To define data models, create an entitydef/ directory inside your application (hello3/ in this case) and create an entitymodel.xml and entitygroup.xml inside your entitydef/ directory:

HelloPerson and HelloHobby each has a primary key, and HelloPersonHobby has two primary key fields, which it uses to link HelloPerson and HelloHobby. It is considered good practice to give your relations a foreign key name to make debugging easier and avoid accidental collision of foreign key names OFBiz generates for you.

It is also very important (but easy to forget) to define these entities in another file, entitygroup.xml, in the entitydef/ directory, so OFBiz will know which delegator, and thus database, to use for them):

Otherwise, the entities will exist in OFBiz, but when you actually try to use them, you will get this error:

org.ofbiz.entity.GenericEntityException: Helper name not found for entity HelloPerson

Finally, you must add this line to your ofbiz-component.xml to let OFBiz know to use this entity as part of this application component, before the <webapp> directive:

<entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel.xml"/>
<entity-resource type="group" reader-name="main" loader="main" location="entitydef/entitygroup.xml"/>

Now start OFBiz. You will see the following lines in your console.log (Linux) or roll past you on your console (Windows), telling you that your entities were loaded:

5336  (main) [            UtilXml.java:242:DEBUG] XML Read 0.0070s: /home/sichen/eclipse/workspace/ofbiz/hot-deploy/hello3/entitydef/entitymodel.xml
5693  (main) [            UtilXml.java:242:DEBUG] XML Read 0.0050s: /home/sichen/eclipse/workspace/ofbiz/hot-deploy/hello3/entitydef/entitygroup.xml

When you go into webtools, you will see the entities:

Click on "All" to the right HelloPerson and you will see its fields:

Notice that next to each field is the Java type and SQL type for this field. The SQL type is specified in the framework/entity/filedtype/ directory and varies depending on the database you are using (mine is Derby.) If there were any values for this entity, it would show below the fields.

Creating Seed Data

Now let's create some seed data for our hobbies. In most OFBiz applications, we would create a data/ directory inside our application and create an XML file for our seed data. Let's call ours HobbiesData.xml:

This file, which is called an entity engine XML file, is a standard OFBiz XML format for importing and exporting data. It is really quite simple. Use the name of the entity ("HelloHobby" in our case) for the tag name, and use the name of the fields as either attributes or as inner tags (see the last value for "WINE." The values for your fields can be the values of the attributes or inside the inner tags, where they can be inside CDATA sections as well, in case you have very long values. Also, the key fields do not have to be upper case or separated by _, but that is the norm in other OFBiz applications.

Now you are ready to load your seed data. Go to the Web Tools application's "Main" screen, and you will see links for "XML Import". Click on "XML Import" and on the next screen, it will prompt you for the name of your file, relative to your ofbiz/ directory. I usually don't click on any of the optional check boxes and just "Import". If you are successful, the same screen will come back and tell you at the bottom how many values were added:

If your import failed, read the error message from your console.log file carefully. It is usually for one of these reasons:

  1. You used a value that was too long for a primary key. The OFbiz "id-ne" is a Java String, but for SQL it is a 20-char VARCHAR.
  2. You missed a required primary key field.
  3. You tried to insert a field which would violate foreign key integrity.

If you read the log carefully you can identify which value (GenericValue) OFBiz was trying to create and what the database error response was. It might also give you a somewhat cryptic foreign-key name to chase down the offending foreign key violation.

You may have also noticed a "XML Export" links on the "Main" page of Web Tools. These links can generate the entity XML files for you.

Now go to "Entity Maintenance" from the "Main" page, click on "All" next to HelloHobby, and you will see the hobbies that were just inserted:

In addition to your fields and values, OFBiz also automatically creates timestamps of when your values were created and updated, for synchronizing data across multiple instances of OFBiz.

Finally, OFBiz can automatically install your seed data during the install process if you add this line to your ofbiz-component.xml file:

    <entity-resource type="data" reader-name="seed" loader="main" location="data/HobbiesData.xml"/>
OFbiz actually lets you define whether your data is "seed", which means they are required for your app to run properly, and "demo", which means they are just for the demo.

Creating Business Logic

Now that we have the data model defined, we can of course write a simple application with a delegator to access the entities directly. Standard practice for OFBiz applications, however, calls for creating a separate layer for the business logic and for creating, updating, and removing entries. The delegator is used directly for looking up values, although more complex lookups are also coded as a service.

Creating services is a two step process. First, you define the service generically in an XML file, which tells the OFBiz service engine what parameters your service takes and where to find it (class and method or location of a script.) Then, you implement the service in Java, the OFBiz minilang, or another scripting language.

Service definitions are usually inside a servicedef/ directory in your application and consists of one or more services.xml files. Here is our services.xml file:

Notice how our services.xml references the entities they work with directly with the <auto-attributes> tag, rather than specifying them outright. This saves you time and makes your application easier to maintain.

You would also need to reference the service resource in your ofbiz-component.xml as well. In addition, you must create <classpath> directives in ofbiz-component.xml to tell it where to load up the apps. This is what our ofbiz-component file looks like, after adding the classpaths, entities definitions, service definitions, and seed data:

Now it looks like ofbiz-component.xml for other OFBiz components, doesn't it?

Now to create the services. A Java service goes inside a src/ directory in your application and is written in a standard fashion: A public class with public static methods which take two parameters, a DispatchContext for getting objects like delegators, dispatchers, locale, and security, and a Map called context which are your input parameters and returns a map of results:

Java services will also need to be compiled, with knowledge of the proper classpaths for other OFBiz apps. This involves using ant and a build.xml build script, which you can usually copy over from another application. It is a standard file in all OFBiz applications and framework components and quite lengthy, so I won't include it here.

When you are done writing your service and creating the build.xml script, you can build your Java services like this:

sichen@linux:~/eclipse/workspace/ofbiz/hot-deploy/hello3> ant
Buildfile: build.xml

init:

clean-lib:
   [delete] Deleting directory /home/sichen/eclipse/workspace/ofbiz/hot-deploy/hello3/build/lib

prepare:
    [mkdir] Created dir: /home/sichen/eclipse/workspace/ofbiz/hot-deploy/hello3/build/classes
    [mkdir] Created dir: /home/sichen/eclipse/workspace/ofbiz/hot-deploy/hello3/build/lib

classpath:

classes:
    [javac] Compiling 1 source file to /home/sichen/eclipse/workspace/ofbiz/hot-deploy/hello3/build/classes

jar:
      [jar] Building jar: /home/sichen/eclipse/workspace/ofbiz/hot-deploy/hello3/build/lib/ofbiz-party.jar

BUILD SUCCESSFUL
Total time: 2 seconds
The build process basically took all your files in the src/ directory, compiled them, and put them into the build/lib directory.

Minilang is much simpler by comparison. The simple minilang service goes inside a script/ directory and is an XML file with directives. Because it is designed especially for common OFBiz application tasks, such as lookup data, store data, check premissions, and work with existing entities and services, it can make those tasks very easy:

Finally, to test it, re-start OFBiz to load all the new definitions in ofbiz-component.xml and services.xml. Then, open a beanshell window and test our service (Note: you should first download bshcontainer.bsh and put it in your ofbiz/ directory):

Here, beanshell called the service dispatcher to run the service, and they were successful, so the right values are created. (Ok, in reality it took about six tries, but I won't bore you with the details.)

So now you have created the data model and services for them. The next step is to put them into the web application.

Creating the Web Application

Our web application will show a guest list of people who have visited the site and allow you to add your name to this list. You can also click on a person and add a hobby for that person from a list of available hobbies. We will build our application with the OFBiz screen-widgets and form-widgets to show you how these tools can build web applications directly from the fields of your data model entities and business logic services, without repetitive HTML code or Java code.

First, let us create two new screens in the screen-widget for our page of people and hobbies. Within each page, there are two forms, one form showing the list of people or hobbies, the other for adding another entry:

Notice here that I am not using a Freemarker page (.ftl) template but instead am calling a form directly. Also, instead of using a .bsh script to look up data from entities, I am using directives such as <entity-and> and <entity-one> in the <actions> part of the screen. Both tools were designed to streamline the process of creating standard forms by reducing the need for display code (such as FTL/HTML) or scripts to find data or call services.

The next step is to define the input elements using the OFBiz form-widget:

The form-widget allows you to define forms based on fields of an entity or parameters of a service, and you can define forms which display a single entity or show a list of data or submit single or multiple values to the controller. You can specify pull down menus and look up related entities, hide fields, place hyperlinks, even calendar buttons and other widgets. Finally, forms can automatically adjust when their related entity or service changes.

I will also take care of adding new requests and views to the controller and a link to the guest book in the header. I've already shown how to do this in the previous tutorial and won't repeat it here. What is different, though, is I need to add the requests to create person and add hobbies to the controller:

These requests go directly to the services we've just defined. There is no need to create your own event servlet method to parse form parameters--OFBiz will do that for you automatically.

Now our application is done. Here is the guestbook page:

and here is the hobbies page:

The look and feel for the site can be significantly improved with the use of stylesheets. All OFBiz display tools, including Freemarker, form-widget, and screen-widget, support stylesheets.

Click to see the list of files for this application.

Maintaining your Application

Finally, a word about maintenance. After your code is written, you've actually just started. Studies show that 50% or more of an application's lifetime costs is long-term maintenance, such as handling user requests for changes or new features. With OFBiz, because the tools from user interface to business logic to data model work together, such changes can be very easy.

For example, suppose that you need to add a new field, "middleName", to your entity for person. All you have to do is add one line for it in your data model, like this:

OFBiz will do the rest for you. When you re-start OFBiz, you will see these lines roll across your screen:

17149 (main) [       DatabaseUtil.java:277:WARN ] Entity "HelloPerson" has 9 fields but table "OFBIZ.HELLO_PERSON" has 8 columns.
17150 (main) [       DatabaseUtil.java:289:WARN ] Field "middleName" of entity "HelloPerson" is missing its corresponding column "MIDDLE_NAME"
17151 (main) [       DatabaseUtil.java:1477:INFO ] [addColumn] sql=ALTER TABLE OFBIZ.HELLO_PERSON ADD MIDDLE_NAME VARCHAR(20)
18013 (main) [       DatabaseUtil.java:302:INFO ] Added column "MIDDLE_NAME" to table "OFBIZ.HELLO_PERSO
It already modified the database for you. Then, when you go to your application again, you will see that the forms have all changed too:

When you submit your request, the service will run with the new field as well.

In other words, with one change in the data model, OFBiz has changed your database, your business logic services, form handling in the controller, and your user interface forms. This is the advantage of using the OFBiz tools for data modeling, business logic, and front-end design as a package. Their mutually aware interactions will not only speed up your development cycle but also significantly reduce your application's long-term maintenance costs.

Conclusions

Now you have built your first complete web application with OFBiz. You have seen first hand how the data modeling, business logic, and user interface tools work together to create an efficient framework for building and, perhaps more importantly, maintaining such applications.


© 2005-2007 Open Source Strategies, Inc. All rights reserved.