Loading presentation...

Present Remotely

Send the link below via email or IM

Copy

Present to your audience

Start remote presentation

  • Invited audience members will follow you as you navigate and present
  • People invited to a presentation do not need a Prezi account
  • This link expires 10 minutes after you close the presentation
  • A maximum of 30 users can follow your presentation
  • Learn more about this feature in our knowledge base article

Do you really want to delete this prezi?

Neither you, nor the coeditors you shared it with will be able to recover it again.

DeleteCancel

Make your likes visible on Facebook?

Connect your Facebook account to Prezi and let your likes appear on your timeline.
You can change this under Settings & Account at any time.

No, thanks

Apache Ofbiz Development

intro to Ofbiz development
by

Jad El Omeiri

on 9 January 2014

Comments (0)

Please log in to add your comment.

Report abuse

Transcript of Apache Ofbiz Development

Ofbiz General Structure
ofbiz\applications
core application ofbiz components
ex: e-commerce, party, ...
to qualify as a core component, a component must be integrated into Ofbiz & contain functions that serve a wide range of users
are so used, they become integral part of Ofbiz
framework components
ofbiz\framework
these components are foundations of Ofbiz
responsible for DB access, caching, rendering screens, managing transactions & low-level tasks used by app. components
not necessary to understand their code. Just how to use the features
special purpose components
these don't qualify as core Ofbiz components
they serve only small fractions of users
Ofbiz should function w/o these since they are functional
ofbiz\specialpurpose
each Ofbiz component has data entity definitions, flow definitions
each component is pretty much self-contained
yet, components need to work with each other
typical Ofbiz component structure may consist of:
configuration files
seed data definitions
entity definition
flow logic
service definition
Java code
web apps
view definition
config
data
entity def
script
service def
web app
widget
build.xml
ofbiz-component.xml
ex:
URI
components are referred via URI
ex: component://comp-name/relative-path
name of component is in definition of component which is in ofbiz-component.xml
N.B: every component has a ofbiz-component.xml
creating component:
usually created in hot-deploy
if in hot-deploy, no need to specify them in component-load.xml
N.B: apps created in applications or framework need to be specified in component-load.xml
MVC architectural pattern
Ofbiz uses the Model-View-Controller (MVC) structure

Model: refers to data structure of the software
used to describe or model a system
a model is a collection of data entities
in a network of relationships w/ each other

View: "outside" of the software
user interface

Controller: is dynamic behavior

note: each Ofbiz component is self-contained &
has its own MVC

MVC in Ofbiz
Model in Ofbiz
is defined in data definition files
ex: ${...}\entitydef\entitymodel.xml
such files should always be in folder entitydef
each component can have 0 or 1 of this folder
==> each component has its own model
between separate models can be have relationships
View in Ofbiz
views or user-interfaces can be in 2 different folders
depending on technologies used!

user-interface definitions are in folder widget
each component can have 1 widget folder
note: Ofbiz sometimes has some
that are misplaced in webapp
folders (mistakes...)
1) when using Ofbiz widget technology
2) when using HTML or FTL technologies
user-interface definitions are in webapp folder
note: this excludes WEB-INF folder
which includes flow/business logic
Controller in Ofbiz
controller or flow or business logic can be in 3 different places, depending on technology
1) when using Java
should be in folder src
2) when using minilang or beanshell
they are in folder script
also in WEB-INF\actions
3) when using Event-Condition-Action (ECA)
in the folder servicedef in secas.xml
when using Service ECA
in folder entitydef in eecas.xml
when using Entity ECA
4) when using Ofbiz services
in folder servicedef & script
in folder servicedef, has files with names servicexxx.xml
they declare usage pattern of services
in folder script or src, there is actual implementation or definition of these services
note: other files are not MVC. some are configuration files. some are seed data files
Widgets (View)
Screen Widgets
Screen widgets:
are the front line of the View element of the MVC architecture
every View in Ofbiz starts with or is contained in a screen
& every screen is defined by a screen widget
to use screen widgets we need to equip our webapp with a screen widget view handler
to do that we need to setup Ofbiz to listen to incoming user requests
(requests like index.html are processed by embedded Tomcat server, but not these!)
to process screen widgets we need to get Ofbiz intercept user requests & perform its special processing
note: Tomcat does not understand screen widgets. screen widgets are part of the Ofbiz framework
Ofbiz intercepts all user requests with an entity called Control Servlet
in WEB-INF\web.xml we set the ControlServlet...
screen widgets are processed by a screen widget handler in Ofbiz
WEB-INF\controller.xml
screen widgets are usually defined in an Ofbiz component's widget folder
the file name convention is xxxscreens.xml
steps
1) xxxscreens.xml:
screen widgets are defined by <screen>
2) inform the control servlet about the screen widget:

in controller.xml we set a dictionary of possible requests
note: the Control Servlet will look in that dictionary to learn about
requests & how to handle them
an entity in that dictionary is called a request map
ex:
<request-map uri= "MyScreen">
<response name= "success" type= "view" value= "MyScreen">
</request-map>
now we need to define that view & point it to the screen widget created earlier
ex:
<view-map name= "MyScreen" type= "screen"
page= "component://apptest/widget/apptest/TheScreens.xml#MyScreen"/>
note: we can have as many <screen> in 1 file
this points to the location of the screen widget & xml file
flow pattern
1) the control servlet receives a request from the user
& looks up its definition in the dictionary of requests
ex: request maps defined by <request-map> in controller.xml

2) after finding the request map that corresponds to incoming request
the control servlet determines the appropriate response
which is defined by <response> inside the <request-map>
this request can point to a view map defined by <view-map>

3) this view map in turn specifies a screen widget to be displayed
anatomy of <section>
<section> is the primary container for the definition of a screen
there must be 1 <section> per screen
<screen name= "AScreen">
<section>

<condition>
<if-compare field= "parameters.show" operator= "equals" value= "key">
</condition>

<actions>
<set-field= "blah" value= "blih"/>
</actions>

<widgets>
<label text= "some text for you. this is ${blah}"/>
</widgets>

<fail-widgets>
<label text= "this is ${blah}"/>
</fail-widgets>

</section>
</screen>
order in controller.xml: must be <include>
<description>
<handler>
<request-map>
<view-map>
sending parameters with requests:
by sending GET parameters in URL
ex: http://localhost:8080/test/control/SomRequest?
paramOne=one&paramTwo=two
note: POST parameters are sent via FORMS using Form Widgets
context & variables:
each screen widget's <actions> operate within their own private context
in that context, all variables are private to that context
utility objects in context: the context contains few objects placed there for our convenience
these objects are important utility objects
utility objects:
screens (used in FreeMarker templates to render sub-screens, defined by screen widgets)
globalContext (one single shared context that all nested screens within a screen can see & use)
nullField (used as null value for DB checks that involve checking for null values in DB fields)
note: not used in beanShell
availableLocales (list of available locales or translation we want Ofbiz to support)
the list is defined in common\config\general.properties property locales.available
locale (is the currently selected locale. based on this value, Ofbiz determines which language to display screens in)
delegator (used to deal with DB)
dispatcher (used to call Ofbiz services)
security (provides a number of tools for security & permission checks)
userLogin (contains details of logged-in user)
parameters (is a map of request parameters. parameters consist of a combination of request attributes, request parameters, session attributes, & ContextServlet attributes)
the local (private) context: accessing the local context of a screen widget is simple
simply assigning a value to a variable in <actions> means creating/modifying the
variable in the local context
ex: <set-field= "blah" value= "blih">
beanShell equivalent
<screen name= "ConditionalScreenWithBsh">
<section>

<condition>
<if-compare field= "parameters.show" operator= "equals" value= "key">
</condition>

<actions>
<script location= "component://testapp/webapp/testapp/WEB-INF/actions/conditionScreenActions.bsh">
</actions>

<widgets>
<label text= "condition passed. Blah is ${blah}"/>
</widgets>

<fail-widgets>
<label text= "condition failed. Blah is ${blah}"/>
</fail-widgets>

</section>
</screen>
in controller.xml, add a request map & view map
in testapp\webapp\WEB-INF\actions\conditionalScreenActions.bsh: String blah= "blih";
note: in beanShell variables are loosely coupled (can have no defined type until assigned a value)
variables created in beanShell or any variables assigned values in beanShell are not carried over to the screen widget
context. need to add: context.put("blah",blah); to .bsh file
the Global context: same way as accessing local context (in <actions>)
in beanShell use: globalContext.put("someGlobalVar1","we can see this in every nested screen");
or: <set field= "global1" value= "this is a GV" global= "true"/>
organizing a large screen into smaller screens
we can create compounded screen widgets that includes multiple other screens
ex:
<screen name= "CompoundScreen">
<section>
<widgets>
<container><include-screen name= "SimpleScreen"/><container/>
<container><include-screen name= "AnotherSimpleScreen"/><container>
</widgets>
</section>
</screen>
in controller.xml add request-map & view map for CompoundScreen
note: in this example other screens are in same TestAppScreen.xml file
if in different file, then specify location
ex: <include-screen name= "XYScreen" location= "component://party:/.../xxx.xml">
Screen Widget's integration with FreeMarker
FreeMarker are powerful for XHTML scripting
FreeMarker files have .ftl extension
to include a FreeMarker document in screen widgets use:
<platform-specific>
<html-template location= "path-to-some-ftl-file"/>
</platform-specific>
specifies where to find the .ftl file
it must point to .ftl (not .html) & the reason is that in fact ftl files are really XHTML files if we ommit all FreeMarker scripts
Screen Widgets as templates:
we can create templates with slots that can include any arbitrary sub-screens
note: since Ofbiz is a web-based app, all output & interfaces should be in
XHTML format
previous widgets we created do not output well-formed XHTML documents
(reason why they show correctly is that usually web-browsers try to correct docs...)
A well formed XHTML doc consists of a DTD (doc type declaration) declaration & the following elements <html>, <head>, <body>, <title>

That means every XHTML doc must be surrounded by a header:

<!DOCTYPE html PUBLIC "..." "http://www.w3....dtd">
<html>
<head>
<title>Ofbiz xhtml doc</title>
</head>
<body>
and a footer:
</body>
</html>
steps:
create folder includes in webapp\testapp folder
create file header.ftl & write into it:
<!DOCTYPE html PUBLIC "..." "http://...dtd">
<html>
<head><title>Some Title</title> </head>
<body>
create screen widget:
<screen name= "header">
<section>
<widgets>
<platform-specific><html>
<html-template location= "component://.../header.ftl"/>
</html></platform-specific>
</widgets>
<section>
</screen>
create the footer:
create the header:
</body>
</html>
in folder includes create file footer.ftl & write into it:
create screen widget:
create footer widget. same as above, but with footer.ftl
use created header & footer
ex: in CompoundScreen screen widget, surround the <include-screen> element
with header & footer
<include-screen name= "header">
<include-screen name= "SimpleScreen">
<include-screen name= "AnotherSimpleScreen">
<include-screen name= "footer">
using Decorator Screen Widgets for templating
Ofbiz uses decorators for templating
the decorator wraps itself around abject to be decorated
decorator acts like template with slots
create decorator: ex: named xhtml-decorator
<screen name= "xhtml-decorator">
<section>
<widgets>
<include-screen name= "header"/>
<decorator-section-include name= "body"/>
<include-screen name= "footer"/>
</widgets>
</section>
</screen>
use the decorator:
<screen name= "CompoundScreen">
<section>
<widgets>
<decorator-screen name= "xhtml-decorator"/>
<decorator-section name= "body"/>
<include-screen name= "SimpleScreen"/>
<include-screen name= "AnotherSimpleScreen"/>
</decorator-section>
</decorator-screen>
</widgets>
</section>
</screen>
note: we can make multiple slots
& even use nested decorators
Form Widgets
Form Widgets are one of many types of View elements that can exist in a screen
Form Widgets are translated into XHTML forms by the Ofbiz screen widget View handler
an XHTML form lets users send POST parameters that are contained in the request itself (not in request's URL)
XHTML form has many types of input fields: text, checkbox, radio button, ...
files & locations:
Form widgets are usually defined in component's widget folder (same as screen widgets)
a Form widget cannot exist outside a screen widget
a screen widget has to: <include-form name= "FirstForm" location= "component://.../MyForms.xml">
we also need to create a request-map & view-map for the screen containing the form
creating the Form widget: in xxxForms.xml create a form widget
ex:
<forms xmlns:xsi="http..." xsi="...widget-form.xsd">
<form name= "FirstForm" type= "single" target= "processFirstForm">
<field name= "firstName"><text/></field>
<field name= "lastName"><text/></field>
<field name= "submit"><submit/></field>
</form>
</forms>
note:we need to include selectall.js in the header.ftl file (a required javascript file for forms submittal)
Form processing via Request Event
a request event is part of a request-map
all processing, especially data-modifying processing, are filed under request event
a request event is declared by <event> & defined by a processing script written in Java, beanShell, Minilang
<event> specifies the processing logic to use to process the incoming request
each request-map can have one request-event
we need to add a request-map in controller.xml
ex:
<request-map uri= "processFirstForm">
<event-type= "java" path= "org.ofbiz.testapp.testapp.MyEvents" invoke= "processFirstForm"/>
<response name= "success" type= "view" value= "OneFormScreen"/>
</request-map>
also add the Java Event Handler, so that control servlet knows how to handle this type of event. above screen handler insert:
<handler name= "java" type= "request" class= "org.ofbiz.webapp.event.JavaEventHandler"/>
create processFirstForm method in learningEvents.java
ex:
public static String pocessFirstForm (HttpServletRequest request, HttpServletResponse response)
{
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
request.setAttribute("combined", firstName + " " + lastName);
request.setAttribute("allParams", UtilHttp.getParameterMap(request));
request.setAttribute("submit", submit);
}
note: after adding java/beanShell codes or scripts, we need to compile the component
other types of Form:
single (already seen)
list (list of forms) (processed each alone)
multi (list of forms but with single submit) (processed altogether)

<alt-target> allows a form to have an alternative action.
is often used when attempting to reuse same form for both "create new record" & "update existing record" scenarios
Other View Element Types in Screen Widgets
Menu Widgets:
are a type of View element inside a screen widget, to display a menu with menu items
in widget folder create MyMenus.xml
<?xml version= "1.0" encoding= "UTF-8" ?>
<menus xmlns:xsi= "http://..." xsi:".../widget-menu.xsd">
<menu name= "TopMenu">
<menu-item name= "SimpleScreen" title= "Simple Screen">
<link target= "SimpleScreen"/>
</menu-item>
</menu>
</menus>
note: the name attribute is used to identify the menu-item
a menu-item can be displayed as "selected" or not
title attribute is what appears in the menu
<link> indicates the request to send to the webapp when menu item is clicked
to include menu into sreen widget:

we can wrap via decorators...
<include-menu name= "TopMenu" location= "component/.../MyMenus.xml">
example:
<screen name= "SimpleScreenWithMenu">
<actions><set field= "tabButtonItem" value= "SimpleScreen"></actions>
<widgets>
<decorator-screen name= "CommonDecorator">
<decorator-section name= "body">
<include-screen name= "SimpleScreen">
<decorator-section>
</decorator-screen>
</widgets>
</screen>
submenus: use <include-menu> to make sub menus in menus

note: <menu> can contain <actions> & should appear 1st under <menu>
used for pre-processing the menu (can call a script...)
The Controller
every webapp has a controller defined in a file web.xml
the controller handles all incoming requests from the end-user
& that's how a webapp listens & responds to the end-user
the controller in an Ofbiz webapp is called a Control Servlet

how Ofbiz hears our requests - the Control Servlet
for each webapp, Ofbiz employs a Front Controller Pattern where a single component serves as a centralized access point & controls all access to the webapp.
This allows Ofbiz to use a uniform processing workflow for all requests fired to any webapp in the entire application ==> consistent reuse of a lot of code & logic in Ofbiz
a typical processing workflow for a request could be like this:
check that the request is valid
perform security checks
log request
perform any process specified
look up the defined processing for the request (defined by a request-map in controller.xml)
process the specified event (if any) for the request
determine the response (depending on prior event, if there was one)
render the response to the web-browser
a lot of standard processing for every request ==> good & cost efficient to use the Front Controller Pattern
the single mechanism (per webapp) employed by Ofbiz to serve the Front Controller Pattern is called a Control Servlet
the Control Servlet is programmed to always perform the above workflow w/o further instructions from the request
no need to understand Front Controller Pattern. just know that 1 & only 1 control servlet is needed per webapp
defining a control servlet
the control servlet is defined in a webapp's web.xml by a <servlet> element
ex:
in ${testapp}\WEB-INF\web.xml

<servlet>
<servlet-name>ControlServlet</servlet-name>
<servlet-class>org.ofbiz.webapp.control.ControlServlet</servlet-class>
</servlet>
note: value of <servlet-name> helps referring to the defined servlet. it must be unique in
web.xml
<servlet-class> defines the implementation of the control servlet. here we're using
Ofbiz's implementation
using the control servlet
by default, all request string patterns are handled by the embedded Tomcat server
we need to define a request string pattern that the control servlet must intercept
& process (we need to map a URL pattern to a control servlet using a <servlet-mapping>)
ex:
<servlet-mapping>
<servlet-name>ControlServlet</servlet-name>
<url-pattern>/control/*</url-pattern>
</servlet-mapping>
note: we can use /SomeOtherName/* so that an https request SomeRequest has a URL
https://localhost:8443/testapp/SomeOtherName/SomeRequest
BUT convention in Ofbiz is to use /control/* pattern
we can use <preprocessor> & <postprocessor> in controller to specify events that run before & after every request
ex:
<preprocessor>
<event type= "java" path= "org.ofbiz.webapp.control.loginWorker" invoke= "checkExternalLogin" />
</preprocessor>
specifying handlers
we can specify handlers for 2 types of programming instructions: request & view
a request instruction defines a request handling procedure that we want our control servlet to execute upon receiving the request. it's defined by a <request-map>
a view instruction defines a procedure of constructing & displaying a ciew to the end-user. it's defined by a <view-map>
(request & view mapping already seen previously)
handlers need to be specified before any request or view map in a config file
ex:
typical handler
<handler name= "java" type= "request" class= "org.ofbiz.webapp.event.JavaEventHandler">
ex:
typical request map using the handler
<request-map uri= "processFirstForm">
<event type= "java" path= "org.ofbiz.testapp.MyEvents" invoke= "processFirstForm"/>
<response name= "success" type= "view" value= "OneFormScreen" />
</request-map>
ex:
typical handler definition for a view map
<handler name= "screen" type= "view" class= "org.ofbiz.widget.ScreenWidgetViewHandler" />
ex:
view map using the handler
<view-map name= "SimpleScreen" type= "screen" page= "component://.../MyScreens.xml#AScreen"
we're telling the control servlet to process that particular view map named SimpleScreen with a handler named screen
request maps
each request-map, defined by <request-map>, defines a procedure with which to process an incoming request
firing a request to Ofbiz is like knocking on a door
Ofbiz first screens the request through some security procedures (some of which can be programmed & customized through the request-map)
if request passes security, Ofbiz performs some logic procedures to determine a response to the request
finally, Ofbiz returns the response to the end-user (often as a screen widget)
knocking the right doors: using uri
ex:
<request-map uri= "forceToHttps">
security before answering: use <security>
with attributes https, auth, direct-request
https:
if set to true, will cause the control servlet to convert an incoming http request to https
by default ="false" (if omitted)
ex:
in controller.xml
<request-map uri= "forceToHttps">
<security https= "true"/>
<response name= "success" type= "view" value= "forceToHttps" />
</request-map>
auth:
if true, will cause control servlet to check if end-user is logged in
checking is done by the control servlet firing an Ofbiz https request to checkLogin
if user not logged in, will be redirected to login screen
after logging in, original request is fired
by default ="false"
direct-request:
if false, causes control servlet to refuse direct calls to a request-map. allows only request-map to be called internally
by default ="true"
Event - determining a response
<event> points to logic & processing that determines a response to the incoming request
3 attributes: type, path, & invoke
type is always needed. it states the event handler to use
path & invoke depend on the event handler used
an invoked request must return a java.lang.String object
this String will determine which of the defined responses to return
each request map can have one or more defined responses
many event handlers in Ofbiz (java, groovy, soap, ...)
Java events
when using java events, we use the event handler org.ofbiz.webapp.event.JavaEventHandler
(previously saw handler defined in controller.xml)
ex:
<handler name= "java" type= "request" class= "org.ofbiz.webapp.event.JavaEventHandler">
to invoke a Java event, path should contain the full name of the java class that contains the java method we want to invoke
invoke must contain the name of that method we want to invoke
ex:
<event type= "java" path= "org.ofbiz.webapp.control.LoginWorker" invoke= "checkLogin"/>
the java method to be invoked, must:
be static
return a java.lang.String
have 2 parameters of type javax.servlet.http.HttpServletRequest & javax.servlet.http.HttpServletResponse
ex:
public static String checkLogin (HttpServletRequest request, HttpServletResponse response)
{
...
return "some string";
}
note: will not go into details about events (deal with security, send feedback to user, messaging, ...)
Response - defining various responses
a response is defined by <response>
6 types of response. view & request are the most used
<response> has 3 attributes: name, type, & value
how a response is chosen
name serves as identifier for the response within a <request-map>
the value of a name has to be unique among all <response> elements within a request map
ex:
request map in controller.xml
<request-map uri="chooseResponse">
<event type="java" path="org.ofbiz.learning.learning.LearningEvents" invoke= "chooseResponse"/>
<response name="success" type="view" value="goodScreen"/>
<response name="error" type="view" value="badScreen"/>
</request-map>
& view maps
<view-map name="goodScreen" type="screen"
page="component://learning/widget/learning/LearningScreens.xml#goodScreen"/>
<view-map name="badScreen" type="screen"
page="component://learning/widgetlearning/LearningScreens.xml#badScreen"/>
Add the screen widgets
In the Java class org.ofbiz.learning.learning.LearningEvents create a new
static method chooseResponse that is invoked in the above request-map
public static String chooseResponse(HttpServletRequest request, HttpServletResponse response)
{
String responseName = (String)request.getParameter("responseName");
if("goodResponse".equals(responseName)) {
return "success";
}
else {
return "error";
}
}
the method returns a String value. this value must correspond to the name of an existing response that is defined in the request-map
the request-map can have any number of responses
note: always good idea to specify a response named error, because the framework returns error by
default if any exception happens in the event
default responses & non-responses
in absence of an <event>, servlet control automatically chooses the "success" response
that's why this works:
<request-map uri= "main">
<response name= "success" type= "view" value= "main" />
</request-map>
if event is present but doesn't return any String value, response will be of type none. no error happens, just a blank screen
view responses:
type view points to a view map

request responses:
type request points to request maps (pass
current request to another map request)
note: no new request is really fired. URL doesn't change

request-redirect:
unlike request, URL will change

request-redirect-noparam:
same as previous, but all parameters
are dropped
View Maps
defined by <view-map>
already familiar with
2 types in Ofbiz:
screen widget (what we know)
screen FOP (for generating PDF output)
The Service Engine
services in Ofbiz operate in a Service Oriented Architecture (SOA)
these services not only have the abillity to invoke other services internally,
but can also be opened up & invoked by remote applications using for
example the widely adopted messaging protocol SOAP
defining a service
in ${testapp}\servicedef\services.xml define firstService

<?xml version="1.0" encoding="UTF-8" ?>
<services xmlns:xsi="http://.../XMLSchema-instance" xsi:SchemaLocation= "http://www.ofbiz.org/dtds/services.xsd">
<description>Learning Component Services</description>
<service name="FirstService" engine="java" location="org.ofbiz.testapp.MyServices" invoke="firstService">
<description>Our First Service</description>
<attribute name="firstName" type="String" mode="IN" optional="true"/>
<attribute name="lastName" type="String" mode="IN" optional="true"/>
</service>
</services>
in ${testapp}\ofbiz-component.xml
add after the last <entity-resource>
this:

<entity-resource type= "model" loader= "main" locaion= "servicedef/services.xml" />
it tells our component testapp to look for service definitions in the file services.xml
note: all service definitions are loaded at startup ==> any change requires a restart
creating the Java code for our service
create class MyServices with a static method firstService
public class MyServices
{
public static final String module = MyServices.class.getName();

public static Map firstService(DispatchContext dctx, Map context)
{
Map resultMap = ServiceUtil.returnSuccess("We called 'firstService' successfully!");
return resultMap;
}
}
services must return a map
this map contains at least one entry
this entry must have the key responseMessage having a value of success, error, fail
by using ServiceUtil.ReturnSuccess() to construct the minimal map, we don't need to bother adding the responseMessage key & value pair
another entry often used is that with the key successMessage
ServiceUtil.returnSuccess("some message") will return a map with entry
successMessage & value of "some message"
testing our service
we may create a screen widget
in controller.xml create a new request-map
<request-map uri= "TestService">
<event type= "service" invoke= "firstService" />
<response name= "success" type= "view" value= "TestService"
</request-map>
note: control servlet still doesn't know how to handle event of type service
in controller.xml add a new handler

<handler name= "service" type= "request" class= "org.ofbiz.webapp.event.ServiceEventHandler"
create a view-map for the screen widget created first
Service Parameters
just like java methods, Ofbiz services can have input & output parameters
just like java methods, parameter types must be declared
input parameters (IN)
<attribute name= "firstName" type= "String" mode= "IN" optional= "true" />
any paramters sent to the service by the end-user (that are not in the list of declared input parameters) will be dropped
other parameters will be converted to a Map by the framework & passed into our static method as the second argument
output parameters (OUT)
services can be declared with OUT parameters
when invoked as events from the controller, parameters are dropped if not declared in our service's definition
ex:
in service definition:
<attribute name= "fullName" type= "String" mode= "OUT" optional= "true" />
& at end of method add:
Map resultMap = ServiceUtil.returnSuccess(message);
resultMap.put("fullName", firstName + " " + lastName);
return resultMap;
two way parameters (INOUT)
a service may change value of IN parameter & we may need a calling service to be aware of that change
instead of declaring same parameter twice as IN & OUT
we just declare it once as INOUT
note: optional attribute indicates if parameter is necessary to successfully run the service or not
calling services from Java code
we saw invoking services as events from the controller
<event type= "service" invoke= "firstService">
we can also call services explicitly from Java code
to do it, we use the dispatcher object
ex:
resultMap = dispatcher.runSync("ServiceTwo");
return resultMap;
add this at end of a service to call a 2nd service
there are 3 ways of invoking a service:
runSync (runs a service synchronously & returns result as a Map)
runSyncIgnore (runs service synchronously & ignores result. nothing is passed back)
runAsync (runs service asynchronously & ignores result)
Synchronous & Asynchronous Services
the service engine allows us to invoke services synchronously or asynchronously

synchronous services will be invoked in the same thread & the thread will wait for the invoked service to complete before continuing
the calling service can obtain info from the synchronously run service (its OUT parameters are accessible)

asynchronous services run in a separate thread & the current thread continues w/o waiting
it starts in parallel
an error in an asynchronous service will not affect the service from which it is called
using the job scheduler
async services can be added to the job scheduler automatically
we can see which services are waiting to run & which have already been invoked, through the Webtools console
we can even schedule services to run only once or recur as often as we want
to test & debug a service quickly, run it synchronously from webtools

note: services must be unique through the entire application
(because we don't need to specify location when when invoking a service)
Event-Condition-Actions (ECA)
the event is the trigger to the action being invoked
2 ECA types in Ofbiz:
service event condition actions (SECAs)
entity event condition actions (EECAs)
SECAs
for SECAs the trigger (event) is a service being invoked
a condition could be if a parameter equalled something (cond. are optional)
SECAs are defined in servicedef/secas.xml
EECAs
the event is an operation on an entity
the action is a service being invoked
EECAs are defined in servicedef/eecas.xml
they are used when it's not necessarily a service that operated on an entity, or if whatever service operates on an entity, an action must be taken
Model
Entites, View Entities, & extended Entities

Apache Ofbiz Development
Finally
Some issues with Ofbiz at RHH
calling external SOAP services
http://ofbiz.135035.n4.nabble.com/calling-external-SOAP-service-from-Ofbiz-td4646036.html
fully explained problem:
probable solution:
http://camel.apache.org/
used to integrate systems...
joining two Databases
actually found an ofbiz-camel project
http://java.dzone.com/articles/connect-apache-ofbiz-real
http://code.google.com/p/camel-soap/wiki/Introduction
according to Ofbiz documentation:
http://ofbiz.apache.org/docs/entity.html#View_Entity_Modeling
All member-entities in a view-entity must be in the same database, but not necessarily in the same entity group.

which means we cannot join two different DB in Ofbiz
http://ofbiz.135035.n4.nabble.com/ViewEntity-across-multiple-databases-td152683.html
other users faced same issue:
solution: deal with it outside of Ofbiz
write code to make the queries & communicate with Ofbiz?

Thank you!
reference:
Wong, Jonathon, and Rupert Howell. Apache OFBiz development the beginner's tutorial. Birmingham, UK: Packt Pub., 2008. Print.
http://www.quizld.com/2012/06/query-multiple-databases-with-one-query-using-unityjdbc-driver/
Model is also known as the DB
the DB stores all info that application is designed to store
Entity Engine in Ofbiz is declarative
it doesn't involve speaking in the native language of many types of DB systems
==> you only need to learn 1 Entity Engine in Ofbiz to work with any of the supported DB systems

Entities
entities are basic units of a Model in MVC
an entity is a single DB table
a table contains info about an entity in the real world (such as person)
a table named Person would contain fields that describe a person
the structure of the Data Model
big data model in Ofbiz
based on "the Data Model Resource Book"
referencing fields of an entity
generally refer to a field of an entity like this: EntityName.FieldName
ex: field street in entity PostalAddress is reference: PostalAddress.street
Ofbiz uses Relational Database Management Systems
Ofbiz uses RDBMS
RDBMS uses the "relational model"
the relational model uses tables that may be related to one another
Entity Engine Concepts
Datasources
a datasource is simply a "source of data"
Derby is the default RDBMS used in Ofbiz
can have multiple DB schemas in one DB instance, each schema housing a separate DB of entities
for DB systems that do not support schemas, separate DB instances will have to be created for that same purpose

Datasources are defined & configured in ${entity}\config\enitityengine.xml
component entity is in folder ${ofbiz}\framework\entity
the default datasource used is localderby:
<datasource name="localderby" helper-class="org.ofbiz.entity.datasource.GenericHelperDAO"
schema-name="OFBIZ" field-type-name="derby"
check-on-start="true" add-missing-on-start="true" use-pk-constraint-names="false"
alias-view-columns="false">
<read-data reader-name="seed"/>
<read-data reader-name="demo"/>
<read-data reader-name="ext"/>
<inline-jdbc
jdbc-driver="org.apache.derby.jdbc.EmbeddedDriver"
jdbc-uri="jdbc:derby:ofbiz;create=true"
jdbc-username="ofbiz" jdbc-password="ofbiz"
isolation-level="ReadCommitted"
pool-minsize="2" pool-maxsize="20"/>
</datasource>
in the datasource localderby, the Derby DB instance is in the folder ofbiz in ${ofbiz}\runtime\data\derby
that is specified by the string ofbiz (part of jdbc:derby:ofbiz) in the attribute jdbc-uri of the element <inline-jdbc>
to create another DB instance, simply create another datasource specifying a different folder (ex: jdbc:another)
the schema name above is OFBIZ
it is not necessary to create another DB instance simply to have separate datasource
Derby supports multiple schemas, so we can have segregated DB using multiple schemas
however, in case of Derby, often useful to have separate DB in separate instances so we can backup or restore each one independently
having 2 DB within 2 schemas inside a single DB instance will mix the 2 into the same folder ${ofbiz}\runtime\data\derby
Entity Delegators
Ofbiz uses an entity delegator to access the database(s)
a delegator is like an administrative object that delegates work to other objects (delegation pattern)
an entity delegator's main purpose is to provide DB access methods for the creation, retrieval, update, & deletion of data (CRUD)
because it's a delegator, it doesn't perform these access tasks itself
instead, it will determine which datasource to use for accessing which
entity groups of entities & then delegate the actual task of accessing those
datasources
entity delegators are defined in ${entity}\config\entityengine.xml
an entity delegator is defined by <delegator>
by default, Ofbiz webapps use the delegator named default:
<delegator name= "default" entity-model-reader= "main" entity-group-reader= "main"
entity-eca-reader= "main" distributed-cache-clear= "false">
<group-map group-name= "org.ofbiz" datasource= "localderby" />
</delegator>
this entity delegator handles only a single entity group named org.ofbiz
the datasource to use for this group is localderby
Entity Groups
an entity group is a group of entities grouped under a group name
the group name is used as a handle for entity delegators to determin which datasource to look into for which entities
only 1 group (org.ofbiz) is used by default by all entity delegators
all enities are under that group
assigning entites to entity groups is in ${testapp}\entitydef\entitygroup.xml
to assign entity PostalAddress to entity group org.ofbiz, write:
<entity-group group= "org.ofbiz" entity= "PostalAddress" />
steps for defining an entity
defininf our entity
entities by default, are defined in entitydef\entitymodel.xml
an entity is defined by <entity>
ex: to create our own entity. in ${testapp} create entitydef\entitymodel.xml
& write:
<?xml version="1.0" encoding="UTF-8"?>
<entitymodel xmlns:xsi="http://www.w3.org/..."
xsi:noNamespaceSchemaLocation= "http://.../entitymodel.xsd">
<entity entity-name="Planet" package-name="org.ofbiz.testapp">
<field name="planetId" type="id-ne"/>
<field name="planetName" type="name"/>
<field name="fromDate" type="date-time"/>
<field name="thruDate" type="date-time"/>
<prim-key field="planetId"/>
<index name="PLANET_NAME_IDX" unique="true">
<index-field name="planetName"/>
</index>
</entity>
</entitymodel>
assigning our entity to an entity group
to put entity under group org.ofbiz
create ${testapp}\entitydef\entitygroup.xml
& write:
<?xml version="1.0" encoding="UTF-8"?>
<entitygroup xmlns:xsi="http:/..." xsi:noNamespaceSchemaLocation= "http://.../entitygroup.xsd">
<entity-group group="org.ofbiz" entity="Planet"/>
</entitygroup>
loading our entity into the Entity Engine
finally need to tell Ofbiz to load our entity definition files (entitymodel.xml & entitygroup.xml)
in file ${testapp}\ofbiz-component.xml, right below the last <classpath>
insert 2 entity resources:
<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" />
<entity-resource> tells Ofbiz to load our entity definition files
those files are called resources in the java context
a resource is any file containing data that can be read by a java app. (in our case Ofbiz)
in general, a resource is like DB data, but can't be changed at runtime
whereas, DB data can be manipulated (by CRUD)
resource data is hard-coded in physical files (like entitymodel.xml)
& changes to these files requires a restart to take effect
attribute reader-name tells Ofbiz to use an <entity-model-reader> named main. This is specified in ${entity}\config\entityengine.xml

note: it's not common to use more than 1 entity model reader
or more than an entity delegator
the single entity model reader defined in Ofbiz is main

attribute loader points to a named <resource-loader>
we insert a <resource-loader> right above the 1st <classpath>, like this:
<resource-loader name= "main" type= "component">

note: <resource-loader> doesn't really create or define a loader
actually, only 1 loader is present
different <resource-loader> with different type attribute cause the
single resource loader to act differently

with the type component for ex. path entitydef\entitymodel.xml will be prepended to for ${ofbiz}\hot-deploy\testapp\entitydef\entitymodel.xml

note: best practice is to use type component for a <resource-loader>
==> keep resource files neatly contained in component's folder
ex: if we use type file, we will have to write our <resource-loader> like this:
<entity-resource type="model" reader-name="main" loader="main"
location=".hot-deploy/testapp/entitydef/entitymodel.xml" />

seeing our Entity
restart Ofbiz to put new entity into DB
to see entity, go to Entity Data Maintenance in webtools
we can create records for our entity from webtools
expiring a value:
instead of removing definitely a value from the DB, we can expire it
==> we can always remember that way, that we had that value
to expire a value, enter for its field thruDate, a value that's before now

un-expiring a value:
change field thruDate to a time in the future
if we want it to un-expire forever, set thruDate to null (delete its value)
Anatomy of <entity>
the attribute name of <entity> is required. it identifies the enitity in the whole entity engine
can't have enities with same name (even if in different groups or packages)
attribute package-name allows Ofbiz to deal differently with entities from different packages

note: mostly used by the entity engine's data sync tool, which is related to Online Analytical
Processing (OLAP) & involves multiple DB machines (1 active & 1 for OLAP)

an <entity> can contain: <field>, <prim-key>, <relation>, & <index> elements (in that order)

note: must have at least 1 <field> element
ex:
<entity entity-name="Planet" package-name="org.ofbiz.learning">
<field name="planetId" type="id-ne"/>
<field name="planetName" type="name"/>
<field name="fromDate" type="date-time"/>
<field name="thruDate" type="date-time"/>
<prim-key field="planetId"/>
<index name="PLANET_NAME_IDX" unique="true">
<index-field name="planetName"/>
</index>
</entity>
<field>
defines fields in an entity
each <field> must at least have attributes name & type
type determines data type that field will & must contain
DB independence
different DBs have different types
Ofbiz achieves DB independence by defining standard "Ofbiz data types" (types that mean something to Ofbiz)
for each Ofbiz data type, Ofbiz has a mapping to an equivalent DB specific data type
==> Ofbiz code deals only with a single set of data types
Ofbiz is in charge of translating its own data types into DB specific ones
the data type mappings are in ${entity}\fieldtype
supported DBs are: Derby, PostgreSQL, MySQL, MSSQL, Oracle, MaxDB, ...
the folder contains one mapping file for each DB Ofbiz supports (for ex: fieldtypederby.xml)
each mapping file is loaded in ${entity}\config by a <field-type>
each field must have a type attribute specified
the type must have a value of one of the Ofbiz data types
the full list of data types is listed in any of the mapping files (ex: fieldtypederby.xml)
in these files each data type is defined by <field-type-def> like this:
<field-type-def type="date-time" sql-type="TIMESTAMP" java-type="java,sql.Timestamp">
<prim-key>
<prim-key> is used to define primary keys for entities
there can be multiple <prim-key> for an entity
<relation>
relationships between entities are defined by <relation> & are called entity relations
creating a relation:
add to an entity :
<relation type="one" fk-name="POST_ADDR_PLANET" rel-entity-name="Planet">
<key-map field-name="planetId"/>
</relation>
each <relation> must have at least 1 <key-map>
type attribute specifies the type of relation
fk-name specifies the name of the foreign key (Ofbiz can automatically create one, if it's not specified)
rel-entity-name points to the other end of the relation
note: relations can be seen from Entity Data Maintenace in webtools
accessing a relation:
with Ofbiz, we don't need to bother finding which fields are linked up
we just tell Ofbiz we want the relation x of the entity y
ex:
<get-related-one value-name="map.postalAddress" relation-name="Planet" to-value-name="plane" />
<get-related-one> tells Ofbiz we want the relation named Planet for the PostalAddress record that we're holding in the variable map.PostalAddress
the related Planet record is placed into the variable planet
<index>
<index> is used to define indexes on fields in entities
ex:
<index name= "PLANET_NAME_IDX" unique= "true">
<index-field name= "planetName">
</index>
note: if unique="true", there's constraint over index
<index-field> specifies which entity field this index is defined on
indexes can be defined over multiple fields
note: you can manually index foreign keys
AS WELL as you can let Ofbiz automatically do that, by setting the use-foreign-key-indices attribute for the datasource to "true"
View Entities
a view entity is a collection of participating or member entities joined together by a number of relations
this collection forms a structure, where every member entity in a view entity is connected to the overall structure. no entity is left out
a view entity provides a single view of a group of interconnected entities

a view entity could possibly be a complex hierarchy of relations between a number of member entities
<view-entity entity-name="GuestHotelOwnerViewL" package-name="org.ofbiz.testapp">
<member-entity entity-alias="HotelGuest" entity-name="PersonL"/>
<member-entity entity-alias="Hotel" entity-name="HotelL"/>
<member-entity entity-alias="HotelOwner" entity-name="PersonL"/>
<view-link entity-alias="HotelGuest" rel-entity-alias="Hotel">
<key-map field-name="housedAt" rel-field-name="id"/>
</view-link>
<view-link entity-alias="Hotel" rel-entity-alias="HotelOwner">
<key-map field-name="ownedBy" rel-field-name="id"/>
</view-link>
</view-entity>
Anatomy of a <view-entity>
a view entity is made up of four parts:
the member entities
the fields (just like fields in an entity)
the view links (the relations that connect member entities together)
the relations (just like the relations an entity has with other entities)
<member-entity>
usually a view entity, has 2 or more member entities
each entity's participation or membership in a view entity is defined by a <member-entity>
ex:
<member-entity entity-alias="HotelGuest" entity-name="PersonL" />
<alias> & <alias-all>
like an entity, a view entity has fields (think of it as a normal entity)
a view entity is accessed/queried same as an entity
a view entity GuestHotelOwnerView can have fields like guestFiestName & hotelName, which are referred as GuestHotelOwnerView.guestFiestName & GuestHotelOwnerView.hotelName
<view-entity entity-name="GuestHotelOwnerViewL" package-name="org.ofbiz.learning">
<member-entity entity-alias="HotelGuest" entity-name="PersonL"/>
<member-entity entity-alias="Hotel" entity-name="HotelL"/>
<member-entity entity-alias="HotelOwner" entity-name="PersonL"/>
<alias entity-alias="HotelGuest" name="guestFirstName" field="firstName"/>
<alias entity-alias="HotelGuest" name="guestLastName" field="lastName"/>
<alias entity-alias="Hotel" name="hotelName" field="hotelName"/>
<alias entity-alias="HotelOwner" name="ownerFirstName" field="firstName"/>
<alias entity-alias="HotelOwner" name="ownerLastName" field="lastName"/>
<view-link entity-alias="HotelGuest" rel-entity-alias="Hotel">
<key-map field-name="housedAt" rel-field-name="hotelId"/>
</view-link>
<view-link entity-alias="Hotel" rel-entity-alias="HotelOwner">
<key-map field-name="ownedBy" rel-field-name="personId"/>
</view-link>
</view-entity>
<alias> example
<alias-all> example
<view-entity entity-name="GuestHotelOwnerViewAllL" package-name="org.ofbiz.learning">
<member-entity entity-alias="HotelGuest" entity-name="PersonL"/>
<member-entity entity-alias="Hotel" entity-name="HotelL"/>
<member-entity entity-alias="HotelOwner" entity-name="PersonL"/>
<alias-all entity-alias="HotelGuest" prefix="guest">
<exclude field="id"/><exclude field="housedAt"/><exclude field="someExtraDetails"/>
</alias-all>
<alias-all entity-alias="Hotel" prefix="hotel">
<exclude field="hotelId"/><exclude field="ownedBy"/>
</alias-all>
<alias-all entity-alias="HotelOwner" prefix="owner">
<exclude field="personId"/><exclude field="housedAt"/><exclude field="someExtraDetails"/>
</alias-all>
<view-link entity-alias="HotelGuest" rel-entity-alias="Hotel">
<key-map field-name="housedAt" rel-field-name="hotelId"/>
</view-link>
<view-link entity-alias="Hotel" rel-entity-alias="HotelOwner">
<key-map field-name="ownedBy" rel-field-name="personId"/>
</view-link>
</view-entity>
note: <alias-all> same as <alias>, but directly inludes all fields
can use <exclude> to exclude certain fields
<view-link>
view links are the connections between member entities in a view entity
a view link is defined by <view-link>
<view-link> has almost same syntax as <relation>
<view-link entity-alias="HotelGuest" rel-entity-alias="Hotel">
<key-map field-name="housedAt" rel-field-name="hotelId"/>
</view-link>
note: must have at least one <key-map> (same as <relation>)
Inner Joins vs. Outer Joins
<view-link> has attribute rel-optional to specify if relation between the joined entities is optional or not
if relation optional true, then all records in the referencing member entity (specified by entity-alias) will be returned in a query to the view entity
if not, only records for which there are related records in the referenced entity (specified by rel-entity-alias) will be returned
<relation>
<relation> elements in a <view-entity> are exactly same as those in <entity>
Applying functions on fields
view entity fields can also contain results of functions, not just member entity fields values. the functions available are:
count, count-disinct, min, max, sum, avg, upper, lower
to use a function, specify it in <alias> element's attribute functon
ex:
<view-entity entity-name="TestAggregate" package-name="org.ofbiz.learning">
<member-entity entity-alias="PA" entity-name="PostalAddress"/>
<alias entity-alias="PA" name="contactMechId" function="count"/>
</view-entity>
Grouping for Summary Views
to group by a field, set the attribute group-by of the element <alias> to true
ex:
<view-entity entity-name="TestGrouping" package-name="org.ofbiz.testapp">
<member-entity entity-alias="PA" entity-name="PostalAddress"/>
<alias entity-alias="PA" name="count" field="contactMechId" function="count"/>
<alias entity-alias="PA" name="city" group-by="true"/>
</view-entity>
Complex Aliases
complex aliases are fields in view entities that involve an operator that takes in 2 or more values (2 or more fields)
examples are +/- : fieldA+fieldB or fieldA-fieldB-fieldC
complex aliases are defined by <alias> elements that have a sub-element <complex-alias>
<complex-alias> should contain 2 or more <complex-alias-field> sub-elements
note: <complex-aliase> can be nested
<member-entity entity-alias="EA" entity-name="SomeEntityAlias"/>
<alias name="complexComputedField">
<complex-alias operator="*">
<complex-alias operator="+">
<complex-alias-field entity-alias="EA" field="a"/>
<complex-alias-field entity-alias="EA" field="b"/>
</complex-alias>
<complex-alias operator="/">
<complex-alias operator="-">
<complex-alias-field entity-alias="EA" field="c"/>
<complex-alias-field entity-alias="EA" field="d"/>
</complex-alias>
<complex-alias-field entity-alias="EA" field="e"/>
</complex-alias>
</complex-alias>
</alias>
ex: (a + b) * ((c - d) / e)
note: operators are DB specific (for ex can't use || to concatenate strings with MySQL, but can do it with Derby)
Extending Entities
Entities can be extended by using <extend-entity>
rather than specifying extensions in the original entitymodel.xml files (that come with Ofbiz), we can put extensions in our own entitymodel.xml file in ${testapp}\entitydef for example
ex:
<extend-entity entity-name="PostalAddress">
<field name="planetId" type="id"></field>
<relation type="one" fk-name="POST_ADDR_PLANET"
rel-entity-name="Planet">
<key-map field-name="planetId"/>
</relation>
</extend-entity>
<relation type="one" fk-name="POST_ADDR_PLANET"
rel-entity-name="Planet">
<key-map field-name="planetId"/>
</relation>
in ${party}\entitydef\entitymodel.xml
in ${testapp}\entitydef\entitymodel.xml
SELECT HotelGuest.firstName as guestFirstName,
HotelGuest.lastName as guestLastName, Hotel.hotelName,
HotelOwner.firstName as ownerFirstName,
HotelOwner.lastName as ownerFirstName
FROM PersonL HotelGuest
INNER JOIN HotelL Hotel ON (HotelGuest.housedAt = Hotel.hotelId)
INNER JOIN PersonL HotelOwner ON (Hotel.ownedBy =
HotelOwner.personId)
SELECT HotelGuest.FIRST_NAME, HotelGuest.LAST_NAME, Hotel.HOTEL_NAME,
HotelOwner.FIRST_NAME, HotelOwner.LAST_NAME FROM
(OFBIZ.PERSON_L HotelGuest INNER JOIN OFBIZ.HOTEL_L Hotel ON
HotelGuest.HOUSED_AT = Hotel.HOTEL_ID)
INNER JOIN OFBIZ.PERSON_L HotelOwner ON Hotel.OWNED_BY =
HotelOwner.PERSON_ID
SQL equivalent
Query produced by Ofbiz
The reason for the difference is that OFBiz produces SQL that will work on a number of databases and so the SQL produced is generic.
Some databases may store case dependent table names and field names and some might not.
For this reason, it was decided that all table names and field names be stored in upper case—removing the case dependency. This is completely removed from us. Unless we are directly querying the database we will never see this, as the framework allows us to use mixed case table and field names and will then convert accordingly, so: hotelName becomes HOTEL_NAME
In this case the framework also takes care of the aliasing of field names.
the Entity SQL Processor in Webtools allows us to type SQL in and check the results. This processor "bypasses" the framework changes to the field names and as such the table and field names must be referenced as they are physically stored (example, HOTEL_NAME).
Accessing the Entities & View Entities
data entities & entity views can be manipulated programmatically (from java code...)
this will be covered later...
Full transcript