Apache OFBiz Service Engine: Part 1

Defining a Service

We first need to define a service. Our first service will be named learningFirstService.

In the folder ${component:learning}, create a new folder called servicedef. In that folder, create a new file called services.xml and enter into it this:

<?xml version="1.0" encoding="UTF-8" ?>

<services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<description>Learning Component Services</description>

<service name="learningFirstService" engine="java"
location="org.ofbiz.learning.learning.LearningServices" invoke="learningFirstService">
<description>Our First Service</description>
<attribute name="firstName" type="String" mode="IN" optional="true"/>
<attribute name="lastName" type="String" mode="IN" optional="true"/>

In the file ${component:learning}ofbiz-component.xml, add after the last <entity-resource> element this:

<service-resource type="model" loader="main" location="service	def/services.xml"/>

That tells our component learning to look for service definitions in the file ${component:learning}servicedefservices.xml.

It is important to note that all service definitions are loaded at startup; therefore any changes to any of the service definition files will require a restart!

Creating the Java Code for the Service

In the package org.ofbiz.learning.learning, create a new class called LearningServices with one static method learningFirstService:

package org.ofbiz.learning.learning;

import java.util.Map;

import org.ofbiz.service.DispatchContext;
import org.ofbiz.service.ServiceUtil;

public class LearningServices {

public static final String module = LearningServices.class.getName();

public static Map learningFirstService(DispatchContext dctx, Map context){

Map resultMap = ServiceUtil.returnSuccess("You have called on service
'learningFirstService' successfully!");
return resultMap;


Services must return a map. This map must contain at least one entry. This entry must have the key responseMessage (see org.ofbiz.service.ModelService.RESPONSE_MESSAGE), having a value of one of the following:

  • success or ModelService.RESPOND_SUCCESS
  • error or ModelService.RESPOND_ERROR
  • fail or ModelService.RESPOND_FAIL

By using ServiceUtil.returnSuccess() to construct the minimal return map, we do not need to bother adding the responseMessage key and value pair.

Another entry that is often used is that with the key successMessage (ModelService.SUCCESS_MESSAGE). By doing ServiceUtil.returnSuccess("Some message"), we will get a return map with entry successMessage of value "Some message". Again, ServiceUtil insulates us from having to learn the convention in key names.

Testing Our First Service

Stop OFBiz, recompile our learning component and restart OFBiz so that the modified ofbiz-component.xml and the new services.xml can be loaded.

In ${component:learning}widgetlearningLearningScreens.xml, insert a new Screen Widget:

<screen name="TestFirstService">
<condition><if-empty field-name="formTarget"/></condition>
<set field="formTarget" value="TestFirstService"/>
<set field="title" value="Testing Our First Service"/>
<decorator-screen name="main-decorator" location="${parameters.mainDecoratorLocation}">
<decorator-section name="body">
<include-form name="TestingServices"
<label text="Full Name: ${parameters.fullName}"/>

In the file ${component:learning}widgetlearningLearningForms.xml, insert a new Form Widget:

<form name="TestingServices" type="single" target="${formTarget}">
<field name="firstName"><text/></field>
<field name="lastName"><text/></field>
<field name="planetId"><text/></field>
<field name="submit"><submit/></field>

Notice how the formTarget field is being set in the screen and used in the form. For now don't worry about the Full Name label we are setting from the screen. Our service will eventually set that.

In the file ${webapp:learning}WEB-INFcontroller.xml, insert a new request map:

<request-map uri="TestFirstService">
<event type="service" invoke="learningFirstService"/>
<response name="success" type="view" value="TestFirstService"/>

The control servlet currently has no way of knowing how to handle an event of type service, so in controller.xml we must add a new handler element immediately under the other <handler> elements:

<handler name="service" type="request" class="org.ofbiz.webapp.event.ServiceEventHandler"/>
<handler name="service-multi" type="request" class="org.ofbiz.webapp.event.ServiceMultiEventHandler"/>

We will cover service-multi services later. Finally add a new view map:

<view-map name="TestFirstService" type="screen" 

Fire to webapp learning an http OFBiz request TestFirstService, and see that we have successfully invoked our first service:

Apache OFBiz Service Engine: Part 1

Service Parameters

Just like Java methods, OFBiz services can have input and output parameters and just like Java methods, the parameter types must be declared.

Input Parameters (IN)

Our first service is defined with two parameters:

<attribute name="firstName" type="String" mode="IN" optional="true"/>
<attribute name="lastName" type="String" mode="IN" optional="true"/>

Any parameters sent to the service by the end-user as form parameters, but not in the services list of declared input parameters, will be dropped. Other parameters are converted to a Map by the framework and passed into our static method as the second parameter.

Add a new method handleInputParamaters to our LearningServices class.

public static Map handleParameters(DispatchContext dctx, Map context){

String firstName = (String)context.get("firstName");
String lastName = (String)context.get("lastName");
String planetId= (String)context.get("planetId");

String message = "firstName: " + firstName + "<br/>";
message = message + "lastName: " + lastName + "<br/>";
message = message + "planetId: " + planetId;

Map resultMap = ServiceUtil.returnSuccess(message);
return resultMap;

We can now make our service definition invoke this method instead of the learningFirstService method by opening our services.xml file and replacing:

<service name="learningFirstService" engine="java" 
location="org.ofbiz.learning.learning.LearningServices" invoke="learningFirstService">


<service name="learningFirstService" engine="java" 
location="org.ofbiz.learning.learning.LearningServices" invoke="handleParameters">

Once again shutdown, recompile, and restart OFBiz.

Enter for fields First Name, Last Name, and Planet Id values Some, Name, and Earth, respectively. Submit and notice that only the first two parameters went through to the service. Parameter planetId was dropped silently as it was not declared in the service definition.

Apache OFBiz Service Engine: Part 1

Modify the service learningFirstService in the file ${component:learning}servicedefservices.xml, and add below the second parameter a third one like this:

<attribute name="planetId" type="String" mode="IN" optional="true"/>

Restart OFBiz and submit the same values for the three form fields, and see all three parameters go through to the service.

Apache OFBiz Service Engine: Part 1



Output Parameters (OUT)

Just like Java methods have return values (although Java methods can have only one typed return value), services can be declared with output parameters. When invoked as events from the controller, parameters will be silently dropped if they are not declared in our service's definition. Add this to our service definition:

<attribute name="fullName" type="String" mode="OUT" optional="true"/>

And in the method handleParameters in org.ofbiz.learning.learning.LearningServices replace:

Map resultMap = ServiceUtil.returnSuccess(message);
return resultMap;


Map resultMap = ServiceUtil.returnSuccess(message);
resultMap.put("fullName", firstName + " " + lastName);
return resultMap;

We have now added the fullName parameter to the resultMap. To see this in action we need to create a new screen widget in LearningScreens.xml:

<screen name="TestFirstServiceOutput">
<actions><set field="formTarget" value="TestFirstServiceOutput"/></actions>
<include-screen name="TestFirstService"/>

Add the request-map to the controller.xml file:

<request-map uri="TestFirstServiceOutput">
<event type="service" invoke="learningFirstService"/>
<response name="success" type="view" value="TestFirstServiceOutput"/>

and finally the view-map:

<view-map name="TestFirstServiceOutput" type="screen" 

Stop OFBiz, rebuild our Learning Component and restart, fire an OFBiz http request TestFirstServiceOutput to webapp learning. Submit your first and last names and planet and notice that now the fullName parameter has been populated.

Apache OFBiz Service Engine: Part 1

Two Way Parameters (INOUT)

A service may change the value of an input parameter and we may need a calling service to be aware of this change. To save us declaring the same parameter twice, with a mode for IN and a mode for OUT, we may use the mode INOUT.

<attribute name="fullName" type="String" mode="INOUT" optional="true"/>

Special Unchecked Parameters

There are a few special cases where IN/OUT parameters can exist even though the service definition does not declare them. They are:

  • responseMessage
  • errorMessage
  • errorMessageList
  • successMessage
  • successMessageList
  • userLogin
  • locale

The parameters responseMessage, errorMessage, errorMessageList, successMessage and successMessageList are necessary placeholders for feedback messages. They must be allowed through all validation checks.

The parameter userLogin is often required for authentication and permissions checks.

The parameter locale is needed just about everywhere in OFBiz. For locale-specificity in certain operations like retrieving template feedback messages, or like formatting numbers and currency figures.

Optional and Compulsory Parameters

The Service Engine checks the validity of the input and the output to ensure that what is coming into the service and is leaving adheres to the service definition. If the optional attribute is set to false and an expected parameter is missing, then the validation will fail and the service will return an error. This transaction will now be marked for rollback, meaning any changes to the database made during this transaction will never be committed. This could include any changes made to the database by calling services. For example:

<attribute name="fullName" type="String" mode="INOUT" optional="false"/>

Here the parameter fullName must be passed into the service and the service must also add this parameter to the resultMap and pass it out or validation will fail and an error will be thrown.

Try changing all of the optional flags on our newly created service to false. After a restart we should see:

Apache OFBiz Service Engine: Part 1

The DispatchContext

We have already seen how parameters are passed into our Java method as a Map. Just as the userLogin object of type GenericValue and the locale object of type Locale were added as attributes to the request for the Java events, both are now automatically added to this context map when the service is invoked in this way.

The first parameter, the DispatchContext, contains the remaining tools we need to access the database, or to invoke other services.

From our Java code we can get access to the following handy objects like this:

GenericValue userLogin = (GenericValue)context.get("userLogin");

Locale locale = (Locale)context.get("locale");

GenericDelegator delegator = dctx.getDelegator();

LocalDispatcher dispatcher = dctx.getDelegator();

Security security = dctx.getSecurity();

For a full list of objects that are available from the DispatchContext, take a look through the code in org.ofbiz.service.DispatchContext.

The service engine is in no way reliant on there being HTTPServletRequest or HTTPServletResponse objects available. Because of this we are able to invoke services outside of the web environment and they can be invoked remotely or scheduled to run "offline".

Service Security and Access Control

Security-related programming in services is exactly like that in events.

In the class org.ofbiz.learning.learning.LearningServices, create a new static method serviceWithAuth:

public static Map serviceWithAuth(DispatchContext dctx, Map context){	
Security security = dctx.getSecurity();
Map resultMap = null;
if (context.get("userLogin") == null ||
!security.hasPermission("LEARN_VIEW", (GenericValue)context.get("userLogin"))) {
resultMap = ServiceUtil.returnError("You have no access here. You're not welcome!");
else {
resultMap = ServiceUtil.returnSuccess("Welcome! You have access!");
return resultMap;

Ensure that the correct imports have been added to the class:

import java.util.Map;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.security.Security;

In the file ${component:learning}servicedefservices.xml, add a new service definition:

<service name="learningServiceWithAuth" engine="java"
location="org.ofbiz.learning.learning.LearningServices" invoke="serviceWithAuth">
<description>Service with some security-related codes</description>

In the file ${webapp:learning}WEB-INFcontroller.xml, add a new request map:

<request-map uri="TestServiceWithAuth">
<security auth="true" https="true"/>
<event type="service" invoke="learningServiceWithAuth"/>
<response name="success" type="view" value="SimplestScreen"/>
<response name="error" type="view" value="login"/>

Rebuild and restart and then fire to webapp learning an http OFBiz request TestServiceWithAuth, login with username allowed password ofbiz, and see the welcome message displayed:

Apache OFBiz Service Engine: Part 1

Logging in with username denied password zibfo will show an error message. Thanks to the request-map's response element named error having a value of login, we are returned back to the login screen:

Apache OFBiz Service Engine: Part 1


In this article we have looked at:

  • Defining and creating services
  • Service parameters
  • Special unchecked (unmatched) IN/OUT parameters
  • Security-related programming

In the next part, we will look at Calling services from Java code, Implementing Service Interfaces, Synchronous and asynchronous services, Using the Service Engine tools, and ECAs: Event Condition Actions.

You've been reading an excerpt of:

Apache OFBiz Development: The Beginner's Tutorial

Explore Title