Complete Guide · 2024 Edition

Moqui Framework

From Zero to Production — Concepts, Architecture, Internals & Code. The only guide you'll ever need.

Architecture JDBC Entity Engine Services Screens Facades Party Model
Chapter 1

What is Moqui?

Moqui is an open-source, Java-based application framework for building enterprise business applications. Think of it as a powerful toolkit that handles all the boring plumbing (database, security, transactions, UI) so you can focus purely on writing business logic.

Core Technology Stack

TechnologyRoleWhy Used
JavaRuntime language, JVM executionStability, performance, enterprise-grade
GroovyDynamic scripting on JVM, service logicConcise, Java-compatible, no recompile
XMLDefine everything — entities, services, screensDeclarative, readable, centralised
FreeMarker (FTL)HTML template renderingPowerful templating, data-driven UI
JDBCDatabase connectivity layerStandard Java DB bridge, works with any DB
JTA / BitronixTransaction managementACID compliance, automatic rollback
HikariCPConnection poolingFast, low-latency DB connection reuse
JCache / HazelcastCaching layerReduces DB hits, improves performance

The Three Golden Rules of Moqui

RuleWhat It Means
Convention over ConfigurationMoqui guesses sensible defaults so you write less boilerplate. E.g., entity MoquiTutorial → table MOQUI_TUTORIAL automatically.
Everything is XMLEntities, services, screens, forms, security rules — all declared in XML. No annotations, no code sprawl.
Declarative, not ImperativeYou describe WHAT you want ("create a Party record"), not HOW to do it (no manual SQL, no manual transaction.begin()).
Chapter 2

How Moqui Works — The 30,000-Foot View

Every request in Moqui travels through exactly 5 layers. Each layer has one job and one job only.

🌐 Browser
HTTP Request
↓ HTTP Request
📄 Screen (UI — XML)
ScreenDefinition
↓ Service Call
⚙️ Service (Business Logic — Groovy/XML)
ServiceDefinition
↓ Entity Operation
🗄️ Entity Engine (ORM — XML)
EntityDefinition
↓ JDBC / SQL
💾 Database (MySQL / PostgreSQL)
JDBC / SQL
📝 Nothing ever skips a layer. The UI never directly touches the DB. Services never build raw SQL. This is the entire philosophy of Moqui in one diagram.
LayerJobKey Object
BrowserUser clicks, submits forms, sends HTTP requestsHTTP Request
ScreenDefines what the user sees (UI in XML), calls services, handles navigationScreenDefinition
ServiceContains ALL business logic — validation, rules, calculationsServiceDefinition
Entity EngineConverts XML entity definitions → SQL, manages CRUDEntityDefinition
DatabasePhysically stores and retrieves data (MySQL, PostgreSQL, etc.)JDBC / SQL
Chapter 3

Boot Sequence — How Moqui Starts Up

When you run ./gradlew run, Moqui goes through a precise startup sequence inside ExecutionContextFactoryImpl (ECFI). Think of ECFI as the restaurant building that opens every morning and sets up everything before the first customer arrives.

#What HappensKey Class
1Read MoquiInit.properties → finds runtime/ directory and conf file pathExecutionContextFactoryImpl
2Parse MoquiDefaultConf.xml → base configuration tree (MNode in memory)initBaseConfig()
3initComponents() → scan component-list, load each component directoryinitComponents()
4initConfig() → merge component MoquiConf.xml + runtime conf into final configinitConfig()
5initClassLoader() → build MClassLoader + GroovyClassLoader chaininitClassLoader()
6new CacheFacadeImpl() → create JCache/Hazelcast cache bucketsCacheFacadeImpl
7new ResourceFacadeImpl() → FTL renderer, Groovy script runner, resource locatorsResourceFacadeImpl
8new TransactionFacadeImpl() → transaction manager (Bitronix by default)TransactionFacadeImpl
9new EntityFacadeImpl() → entity definitions loaded from ALL entity/*.xml filesEntityFacadeImpl
10new ServiceFacadeImpl() → service runners registered; SECA rules loadedServiceFacadeImpl
11new ScreenFacadeImpl() → screen caches initialized; FTL widget templates loadedScreenFacadeImpl
12postFacadeInit() → warm caches, start scheduled job runner, everything readypostFacadeInit()
📝 ECFI is created once when the server starts. It lives until the server shuts down. All facades hang off this one object.
Chapter 4

Configuration Files — How They Load

Moqui configuration is layered. Each layer overrides the previous one. Think of it like CSS specificity — more specific configs win.

MoquiDefaultConf.xml
Framework built-in defaults — never edit this
↓ overridden by
MoquiDevConf.xml
Your dev overrides: DB creds, debug flags, local JDBC settings
↓ overridden by
MoquiActualConf.xml
Production overrides: real DB host, passwords, production DB
↓ merged with
Component MoquiConf.xml
Per-component config — datasource groups, entity groups

JDBC Configuration Example

<datasource name="defaultDS" database-conf-name="mysql">
  <inline-jdbc
    jdbc-driver="com.mysql.cj.jdbc.Driver"
    jdbc-uri="jdbc:mysql://127.0.0.1:3306/moqui"
    jdbc-username="moqui"
    jdbc-password="@12345abC"/>
</datasource>
Chapter 5

XML — The Language of Moqui

In Moqui, XML is not "config". It is the programming language. You don't write Java classes to define a database table — you write XML. You don't write controller methods — you write XML transitions.

Adarsh's Types of XML Artifacts

XML TypeFile PatternWhat It Defines
Entity XMLentity/*.xmlDatabase tables, columns, relationships, indexes, seed data
Service XMLservice/*.xmlBusiness operations — inputs, outputs, logic, transactions
Screen XMLscreen/*.xmlUI pages, forms, lists, navigation, transitions
SECA XML*.secas.xmlEvent → Condition → Action rules (auto-trigger services)
Data XMLdata/*.xmlSeed and demo data records loaded into DB on startup
REST XML*.rest.xmlExposes services as REST API endpoints

The Fundamental Rule: XML is NEVER Executed Directly

XML File on Disk
↓ Parsed by MNode parser (SAX-based, fast)
MNode Tree in RAM
↓ Converted to Definition Objects
EntityDefinition / ServiceDefinition / ScreenDefinition
↓ Actions compiled to Groovy bytecode
JVM Class (cached forever)
↓ Executed on every request
Result returned
📝 The XML file is read once. The result is cached in memory. The original file is never re-read at runtime unless you're in dev mode.
Chapter 6

Facade Pattern — The Backbone of Moqui

A Facade is a simple, clean front door to a complex system. Instead of writing 50 lines of JDBC code to run a query, you call ec.entity.find("party.Party").list() — and Moqui handles the 50 lines for you.

FacadeYou WriteWhat It Hides
EntityFacade
ec.entity
ec.entity.find("party.Party").list()SQL generation, JDBC connections, connection pooling, result set mapping, caching
ServiceFacade
ec.service
ec.service.sync().name("create#Person").call()Service discovery, parameter validation, transaction management, SECA rules
ScreenFacade
ec.screen
Auto-rendered from XMLFreeMarker templates, form rendering, navigation, widget rendering
TransactionFacadeAuto-managedJTA transaction begin/commit/rollback, XA transactions, savepoints
CacheFacade
ec.cache
ecfi.cacheFacade.getCache("my.cache")JCache internals, eviction policies, expiry, distributed caching
ResourceFacade
ec.resource
ec.resource.groovy.script()File reading, FTL rendering, Groovy compilation, resource locators
LoggerFacade
ec.logger
ec.logger.info("msg")Log4j2 internals, log levels, log routing
📝 All facades are created once at boot inside ECFI and shared across ALL requests. They are thread-safe. You never create a facade — you always use the one ec gives you.
Chapter 7

ExecutionContext (ec) — Your Runtime Buddy

ExecutionContext is the most important object you'll use in Moqui. It is your handle to everything — the current user, the database, services, the web request, error messages, and all facades. It lives for exactly ONE request and is destroyed after.

The Restaurant Analogy

Moqui ConceptRestaurant EquivalentKey Behaviour
ExecutionContextFactory (ECFI)The restaurant buildingOne per server. Never changes. Lives forever.
ExecutionContext (EC)One customer's table + waiterOne per request/thread. Created fresh. Destroyed after request.
Facade (EntityFacade etc.)Kitchen department headOne per server. Shared. Thread-safe. Accessed via ec.entity etc.
Definition (EntityDefinition)The recipe cardCreated from XML once. Cached permanently. Never changes.
ContextStackWaiter's notepadVariables set during this request only. Read top-to-bottom.

What EC Holds (Per-Request State)

PropertyTypeWhat It Carries
ec.userUserFacadeImplCurrent logged-in user, roles, permissions
ec.contextContextStackAll variables in scope for this request (like a stack of Maps)
ec.messageMessageFacadeImplErrors and info messages accumulated during this request
ec.webWebFacadeImplHTTP request object, response, session, cookies, URL params
ec.entityEntityFacadeImplDatabase operations — shared facade, accessed per-request
ec.serviceServiceFacadeImplService calls — shared facade, accessed per-request
⚠️ EC is NEVER shared between threads. Two simultaneous users each get their own EC. But both share the same EntityFacade, ServiceFacade, etc.
Chapter 8

Entity Engine — The Database Layer

The Entity Engine is Moqui's built-in ORM. You write zero SQL. You define your database tables in XML, and the Entity Engine does everything else — creates tables, runs queries, manages relationships, handles caching.

Core Entity Engine Operations

OperationMoqui CodeGenerated SQL
Createec.entity.makeValue("party.Party").setAll([...]).create()INSERT INTO PARTY (...) VALUES (...)
Read Oneec.entity.find("party.Party").condition("partyId","P1").one()SELECT * FROM PARTY WHERE PARTY_ID = 'P1'
Read Manyec.entity.find("party.Person").list()SELECT * FROM PERSON
UpdatepartyValue.set("statusId","INACTIVE").update()UPDATE PARTY SET STATUS_ID='INACTIVE' WHERE PARTY_ID='P1'
DeletepartyValue.delete()DELETE FROM PARTY WHERE PARTY_ID = 'P1'
Auto-service createec.service.sync().name("create#party.Party").call()INSERT INTO PARTY (...) — zero code needed

Entity Engine vs Raw JDBC vs Hibernate

FeatureRaw JDBCHibernateMoqui Entity Engine
SQL WritingManual (you write every query)Generated from annotationsGenerated from XML definition
BoilerplateVery high (connections, PS, RS)Medium (session management)None — just call find/create
ConfigurationManual everywhereAnnotations in codeCentral XML files
TransactionsManual begin/commit/rollbackSession-levelAutomatic, JTA-backed
DB IndependenceNo — SQL varies by DBPartial — dialect dependentFull — same XML for all DBs
CachingNo — you build it yourself2-level cache (optional)Built-in, configurable per entity
Chapter 9

Entity XML — Complete Tag Reference

This is the master reference for every tag and attribute in a Moqui entity XML file.

9.1 <entity> Tag — The Root

The <entity> tag simultaneously defines: a database table, a Java object blueprint, and all framework-level rules for that data.

<entity entity-name="Party" package="party">

use — Entity Behaviour Type

use valueWhen to UseCachingExample Entities
transactional (default)Financial/operational data where accuracy is critical❌ Not cachedorders, payments, inventory transactions
nontransactionalMaster/reference data that changes rarely✅ Can be cachedParty, Product, Customer
configurationFramework and app config settings✅ Heavily cachedsystem settings, enumeration types
analyticalReporting/aggregated data derived from transactional dataOptionalsales summaries, dashboards
loggingHigh-volume log records, audit trails❌ Never cachedaudit logs, event logs

Primary Key Generation Attributes

AttributeWhat It DoesDefault / Example
sequence-primary-use-uuidtrue → use UUID (globally unique), false → sequential integerDefault: false → 1001, 1002...
sequence-bank-sizePre-fetches N IDs from DB at once to avoid a DB hit on every insertDefault: 50
sequence-primary-staggerMakes IDs jump randomly in range 1 to N, preventing predictable IDsstagger=5 → 1001, 1003, 1008...
sequence-primary-prefixAdds a text prefix to every generated IDprefix=ORD_ → ORD_1001

authorize-skip — Security Override

ValueWhat Gets Skipped
false (default)Nothing skipped — full permission check always runs
trueALL checks skipped (create, update, delete, view) — dangerous, use with care
createOnly CREATE permission check skipped — useful for anonymous user registration
viewOnly VIEW (read) check skipped — good for public data that anyone can see
view-createBoth VIEW and CREATE skipped — for entities anyone can read and create

9.2 <field> Tag — Column + Behaviour

AttributePurposeNotes
name (required)Field/property name in codeAlways camelCase
type (required)Abstract data type — Moqui maps to Java type → SQL typeid, text-short, date-time, number-decimal, etc.
is-pktrue = this is a primary key column. Can have multiple fields as composite PKAdds PK + unique index
not-null="true"DB-level NOT NULL constraintThrows error if null submitted
encrypt="true"Value is stored encrypted in DB. For passwords, tokens, sensitive dataDecrypted transparently on read
defaultGroovy expression evaluated when value is null on create/updatedefault="nowTimestamp()"
create-only="true"Once set on create, this field's value can never be changedLike a write-once field

9.3 <relationship> Tag — Entity Joins

type AttributePurpose
type="one"One record on the related side. Like a FK: Order → Customer. Enforces FK constraint in DB.
type="many"Multiple records on the related side. Like: Customer → Orders.
type="one-nofk"One related record, but NO FK constraint in DB. Use for optional relationships or legacy DB compatibility.
<relationship type="one" related="Customer">
  <key-map field-name="customerId" related="customerId"/>
</relationship>

9.4 <view-entity> — Joins & Complex Queries

Child TagSQL EquivalentPurpose
<member-entity>FROM / JOIN clauseDefines which entities/tables participate and how they join
<alias>SELECT column AS nameSelects a specific field, optionally with aggregation
<alias-all>SELECT alias.*Pulls ALL fields from a member entity into the view
<entity-condition>WHERE clauseFilters records — static conditions built into the view
📝 join-optional="true" = LEFT JOIN. Without it = INNER JOIN.
Chapter 10

Field Types — The Complete Mapping

Moqui maps types through a 3-step chain: Moqui Abstract Type → Java Type → Database-Specific SQL Type. This is what makes Moqui database-independent.

id
String
VARCHAR(60)
Primary keys, foreign keys, short identifiers
id-long
String
VARCHAR(255)
Long identifiers, external IDs
text-short
String
VARCHAR(63)
Short strings: names, codes, status values
text-medium
String
VARCHAR(255)
Standard strings: descriptions, titles, URLs
text-long
String
TEXT (up to 65K)
Long text: notes, descriptions, HTML content
text-very-long
String
LONGTEXT (up to 4GB)
Very large text: XML, JSON blobs, article bodies
date-time
java.sql.Timestamp
DATETIME
Full timestamp: created date, order date
number-integer
Long
DECIMAL(20,0)
Whole numbers: quantity, count, sequence
currency-amount
BigDecimal
DECIMAL(22,2)
Money values (2 decimal places): price, tax
text-indicator
String
CHAR(1)
Y/N boolean indicators (Moqui style for flags)
⚠️ Never use number-float for money! Floating point arithmetic is imprecise. 0.1 + 0.2 ≠ 0.3 in float. Always use currency-amount for financial values.
Chapter 11

JDBC in Moqui

JDBC (Java Database Connectivity) is the standard Java API for talking to relational databases. Moqui's Entity Engine uses JDBC internally — you almost never touch it directly.

Standard JDBC 6-Step Workflow (What Moqui Does Internally)

#ActionCode Example
1Load DriverClass.forName("com.mysql.cj.jdbc.Driver")
2Get ConnectionDriverManager.getConnection("jdbc:mysql://...")
3Create Statementconn.prepareStatement("SELECT * FROM PARTY")
4Execute Queryps.executeQuery()
5Process Resultswhile(rs.next()) { rs.getString("PARTY_ID"); }
6Close Connectionconn.close() — actually returns to HikariCP pool

Common JDBC Errors & Fixes

ErrorCauseFix
ClassNotFoundExceptionJDBC driver JAR missingAdd mysql-connector-java.jar to runtime/lib/
Connection refusedMySQL not running / wrong host or portStart MySQL service, verify host:port in config
Access denied for userWrong credentials or missing DB grantCheck username/password; run GRANT ALL ON moqui.* TO ...
No suitable driver foundDriver class name typoVerify jdbc-driver attribute in config exactly matches
Chapter 12

Moqui ↔ MySQL Integration

Character Set — UTF-8 vs UTF8MB4

TypeMax Bytes/CharEmoji SupportUse When
utf8 (MySQL)3 bytes❌ NoLegacy apps only — avoid for new projects
utf8mb4 (MySQL)4 bytes✅ Yes — full UnicodeAlways use this for modern applications

What ./gradlew load Does

StepWhat Happens
1Gradle reads build scripts, identifies the load task, sets up classpath
2Starts embedded Jetty server, loads MoquiDevConf.xml + MoquiActualConf.xml
3Reads ALL entity/*.xml files from all components, builds EntityDefinition objects
4Connects via JDBC using configured credentials
5Compares entity definitions with existing DB schema → generates CREATE TABLE or ALTER TABLE SQL
6Reads all <seed-data> blocks from entity XML files → generates INSERT SQL → executes
7If demo data flag set → loads additional demo records
📝 Run ./gradlew load when: first setup, adding new entities, adding new seed data. It's safe to run multiple times — it only creates missing tables/columns.
Chapter 13

Party Data Model — Enterprise Design

The Party model is the foundation of enterprise ERP/CRM systems. Instead of having separate Customer, Vendor, Employee, Organization tables (which causes duplication and rigid structure), Moqui uses a single abstract 'Party' concept.

Imagine: A company (ACME Corp) is your customer AND your supplier. With traditional separate tables, you'd need two records and they'd get out of sync. With Party model, ACME Corp is ONE Party record — it just has relationships saying it's both a customer and a supplier.

Party (abstract base)
Any actor in the system
├── Person (an individual human)
└── PartyGroup (a company / organization)
ContactMech
How to contact any Party
├── Email Address
├── Phone Number
└── Postal Address

Design Patterns in the Party Model

PatternWhere UsedBenefit
Subtype PatternParty → Person / PartyGroupShared identity (partyId), specialised fields per type, no duplication
Enumeration PatternpartyTypeEnumId, contactMechTypeIdTypes are data, not columns — add new types without DB schema change
Valid-Time ModelingPartyContactMech (fromDate, thruDate)Full history preserved, no data loss, auditable
Join TablePartyContactMechMany-to-many: one party has many contacts, one contact can be shared
📝 To 'change' an email: set thruDate on old record = today, create new PartyContactMech with fromDate = today. Old email is preserved for history!
Chapter 14

Service Layer — Business Logic

A Service in Moqui is NOT just a function. It is a fully managed execution unit that includes: business logic + input validation + transaction management + security + error handling.

Service Naming Convention

// path + verb + noun:
myapp.PersonServices.create#Person
// call it:
ec.service.sync().name("create#Person").call()

Service Control Attributes — Authentication

Attribute & ValueMeaning
authenticate="true" (default)User must be logged in. Full authorization check runs.
authenticate="false"No login required. Auth check is completely skipped.
authenticate="anonymous-all"No login required. Logs in as anonymous user. All actions authorized.
authenticate="anonymous-view"No login required. Logs in as anonymous. Only VIEW action authorized.

Transaction Control

AttributeOptions & Meaning
transactionuse-or-begin (default): join existing TX or start new one. new: always start fresh TX. ignore: no TX management.
transaction-timeoutSeconds before auto-rollback. Override per-service for long operations.

Concurrency Control (Semaphore)

semaphore valueBehaviourUse Case
none (default)No locking — multiple instances can run simultaneouslyMost services
failIf same service is already running → immediately throw errorPrevent duplicate processing
waitIf same service is already running → wait until it finishesSerial queue behaviour
Chapter 15

Service Types — All 6 in Detail

typeLogic LocationWhen to Use
inline (default)<actions> block inside XMLMost common — small to medium business logic
entity-autoNo code — auto-generatedCRUD on any entity, zero boilerplate needed
scriptExternal .groovy fileLarge logic, reusable across services
javaCompiled Java class methodPerformance-critical code, existing Java libraries
remote-json-rpcExternal JSON-RPC serverCall another Moqui instance or JSON-RPC API
remote-restExternal REST HTTP endpointCall any REST API (Stripe, Twilio, custom APIs)

entity-auto — Zero Code CRUD

CallWhat It DoesSQL Generated
ec.service.sync().name("create#party.Party").call()Creates a Party recordINSERT INTO PARTY (...)
ec.service.sync().name("update#party.Party").call()Updates a Party recordUPDATE PARTY SET ...
ec.service.sync().name("delete#party.Party").call()Deletes a Party recordDELETE FROM PARTY WHERE ...
ec.service.sync().name("store#party.Party").call()Create or Update (upsert)INSERT or UPDATE depending on PK

Calling Services — 3 Modes

ModeCodeWhen to Use
Synchronousec.service.sync().name("create#Person").parameters([...]).call()Most cases — wait for result
Asynchronousec.service.async().name("send#Email").parameters([...]).call()Background tasks — fire and forget
Async Distributedec.service.async().name("process#Report").distribute(true).call()Cluster deployments — run on another server

SECA Rules — Auto-Trigger Services

<!-- In a seca.xml file -->
<seca service="create#party.Person" when="post">
  <action service="send#WelcomeEmail">
    <field-map field-name="toEmail" from="email"/>
  </action>
</seca>
Chapter 16

Screen Layer — UI Definition

Screens are Moqui's UI layer. You define the entire user interface in XML — forms, lists, dialogs, navigation — and Moqui renders it as HTML.

Screen XML Key Tags

TagPurpose
<screen>Root tag — defines one UI screen
<transition>Handles form submissions and button clicks (HTTP POST handler)
<actions>Runs before rendering — loads data into context
<widgets>Defines the visual UI components
<form-single>Form for creating or editing one record
<form-list>Displays a list of records in a table
<container-dialog>Creates a button that opens a modal dialog
<auto-fields-entity>Auto-generates form fields from entity definition

Action Tags — Logic in XML

Action TagGroovy/SQL EquivalentExample
<entity-find>SQL SELECT / ec.entity.find()<entity-find entity-name="party.Party" list="partyList">
<entity-find-one>SQL SELECT + .one()<entity-find-one entity-name="party.Party" value-field="party">
<service-call>ec.service.sync().name()<service-call name="create#party.Party" out-map="result"/>
<set>Variable assignment<set field="statusId" value="ACTIVE"/>
<if>if/else statement<if condition="party != null">...</if>
<script>Inline Groovy code<script>ec.logger.info("Running")</script>
Chapter 17

Screen XML — PartyScreen.xml Walkthrough

A complete, line-by-line walkthrough of a real Moqui screen that displays a list of Party records and lets you create new ones.

Screen Root — Authentication

<screen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/xml-screen-2.1.xsd"
  require-authentication="anonymous-all">

Transition — Handling Form Submission

<transition name="createParty">
  <service-call name="create#party.Party"/>
  <default-response url="."/>
</transition>

Actions — Loading Data Before Render

<actions>
  <entity-find entity-name="party.Party" list="partyList">
    <search-form-inputs/>
  </entity-find>
</actions>

Widgets — The UI

<widgets>
  <container-dialog id="CreatePartyDialog" button-text="Create Party">
    <form-single name="CreateParty" transition="createParty">
      <auto-fields-entity entity-name="party.Party" field-type="edit"/>
      <field name="submitButton">
        <default-field title="Create"><submit/></default-field>
      </field>
    </form-single>
  </container-dialog>

  <form-list name="ListParty" list="partyList" skip-form="true">
    <auto-fields-entity entity-name="party.Party" field-type="find-display"/>
  </form-list>
</widgets>

End-to-End Flow: User Creates a Party

#What HappensMoqui Component
1User opens /apps/myapp/PartyScreenScreenFacadeImpl resolves URL
2Actions run: entity-find loads partyList from DBEntityFacade → JDBC → DB
3form-list renders partyList as HTML tableFreeMarker template → HTML
4User clicks 'Create Party' buttoncontainer-dialog opens modal
5User fills form and clicks CreateBrowser POSTs form data
6Transition 'createParty' receives POSTScreenDefinition.TransitionItem
7create#party.Party entity-auto service runsEntityAutoServiceRunner → INSERT
8default-response url="." → reload screenScreenRenderImpl re-renders
9Updated list shown (new record visible)entity-find reruns, FTL rerenders
Chapter 18

Creating Forms & Services — Hands-On

PersonServices.xml — The Contract

<service verb="create" noun="Person" type="script"
  location="component://party/service/party/createPerson.groovy">
  <in-parameters>
    <parameter name="partyId" type="String" required="true"/>
    <parameter name="firstName" type="String" required="true"/>
    <parameter name="lastName" type="String" required="true"/>
    <auto-parameters entity-name="party.Person" include="all"/>
  </in-parameters>
  <out-parameters>
    <parameter name="responseMessage" type="String"/>
  </out-parameters>
</service>

createPerson.groovy — The Logic

// All in-parameters are auto-injected into context
def partyId = parameters.partyId
def firstName = parameters.firstName
def lastName = parameters.lastName

// Check if Party exists
def party = ec.entity.find("party.Party")
    .condition("partyId", partyId).one()
if (!party) {
    context.responseMessage = "Party ${partyId} does not exist"
    return
}

// Create the Person record
ec.entity.makeValue("party.Person")
    .setAll(parameters)
    .create()

context.responseMessage = "Person ${firstName} ${lastName} created successfully"
Chapter 19

XML Processing Pipeline — What Becomes What?

File TypeCompiled?When ProcessedResult Cached?
Entity *.xmlNo (→ MNode → EntityDefinition)StartupYes (permanent)
Service *.xmlPartially (MNode → SD; <actions> → Groovy Class)First call (lazy)Yes
Screen *.xmlPartially (MNode → ScreenDef; <actions> → Groovy Class)First request (lazy)Yes, with mod-check
Standalone *.groovyYes (→ in-memory JVM Class)First call (lazy)Yes
Inline Groovy in XMLYes (entire <actions> → one Class)First call (lazy)Yes
*.java (framework)Yes (ahead of time, by Gradle)Build timePermanent (in JAR)
*.ftl templateParsed (→ FTL Template object)First useYes
SECA *.secas.xmlNo (→ ServiceEcaRule objects)StartupYes (in-memory Map)

ClassLoader Chain

Bootstrap ClassLoader
JDK built-ins
└──
System ClassLoader
└──
MClassLoader
Loads JARs from runtime/lib, component/lib
└──
GroovyClassLoader
Extends MClassLoader — Compiles .groovy dynamically at runtime
Chapter 20

Groovy in Moqui

The Three Groovy Tools — Which Does Moqui Use?

ToolAnalogyDoes Moqui Use It?
GroovyShellCalculator — type expression, get answerRarely (one-off expressions only)
GroovyScriptEngineScript file watcher — re-compiles on file change❌ Not used by Moqui
GroovyClassLoaderJava class loader that also compiles Groovy✅ YES — Moqui's ONLY compilation tool

Available Variables in Groovy Scripts

VariableTypeWhat It Is
ecExecutionContextThe main context object — access to everything
parametersMap<String, Object>Input parameters passed to this service
contextContextStack (Map-like)The shared context — set values here to return as out-parameters
ec.entityEntityFacadeDatabase operations
ec.serviceServiceFacadeCall other services
ec.loggerLoggerFacadeLogging: ec.logger.info(), ec.logger.warn()
ec.messageMessageFacadeAdd error/info messages: ec.message.addError()
📝 The Class is NEVER re-created per request. Only a lightweight Script wrapper is new each time. After the first call, Groovy service performance ≈ Java performance.
Chapter 21

Definition vs Facade vs EC — The Mental Model

ConceptAnalogyLifetimeShared?Purpose
Definition (EntityDef, ServiceDef, ScreenDef)Recipe card — written once, read-onlyPermanent (until server restart)Yes — all threads read the sameDescribes WHAT something is
Facade (EntityFacade, ServiceFacade, etc.)Kitchen department head — knows where everything isPermanent (created at boot)Yes — one per server, thread-safeProvides clean API to a complex subsystem
ExecutionContext (ec)Waiter assigned to one table — lives for one customer's visitPer-request (created & destroyed each time)No — each request gets its own ECCarries state for ONE request

One-Liner Summaries

Definition
What an entity/service/screen IS — static blueprint, cached forever, never changes at runtime.
Facade
How you INTERACT with a subsystem — shared coordinator, always available, thread-safe.
ExecutionContext (ec)
WHO is making the request and WHAT is happening NOW — carries state for one specific request.
Chapter 22

Key Design Patterns in Moqui

Facade Pattern
EntityFacade, ServiceFacade, ScreenFacade
Hides complexity behind a simple API. You call 1 line, 50 lines run internally.
Strategy Pattern
ServiceRunner (Inline/Java/Script/EntityAuto)
Each service type is a different strategy for executing logic. Switchable without changing calling code.
Singleton Pattern
ECFI, all Facades
One instance per server. Shared globally. Thread-safe.
Factory Pattern
ECFI.getEci()
Creates new ExecutionContext instances for each request.
Subtype Pattern
Party → Person / PartyGroup
Shared base record (Party), type-specific child record (Person). Shared PK links them.
Enumeration Pattern
partyTypeEnumId, statusId, contactMechTypeId
Types are data rows, not hardcoded columns. Add new types without schema changes.
Valid-Time Modeling
PartyContactMech (fromDate, thruDate)
Historical data preserved with date ranges. No records ever deleted — just expired.
Declarative Programming
All XML definitions
You say WHAT, Moqui figures out HOW. Zero SQL, zero JDBC, zero HTML for basic operations.
Chapter 23

Common Mistakes & Debugging

Entity Mistakes

MistakeSymptomFix
Wrong entity name in codeEntityException: Entity not found "party.Pary"Check spelling + package. Use exact case.
Not running ./gradlew load after adding entityTable doesn't exist — SQL error on first queryAlways run ./gradlew load after adding/modifying entity XML.
Using float for currencyPrice shows as 99.99999... instead of 100.00Use currency-amount type, not number-float.
Missing relationship key-mapJoin produces no results or wrong join conditionEnsure <key-map field-name="x" related="y"/> is present.
Caching transactional dataStale data shown after updateNever use cache="true" on transactional entities (orders, payments).

Service Mistakes

MistakeSymptomFix
Wrong service name formatServiceException: Service not found "PersonService.create"Use verb#noun format: "create#Person"
Missing required parameterValidation error at framework levelPass all required="true" parameters in your call.
allow-remote not set for REST404 or access denied from REST APIAdd allow-remote="true" to the service definition.
Wrong Groovy context variable nameNull value returned for out-parameterIn Groovy, set context.myOutput = value, not parameters.myOutput.
Chapter 24

Interview Cheatsheet

Adarsh's Core Architecture Questions

What is Moqui?
An open-source Java enterprise framework. Everything is defined in XML. Uses convention over configuration. Built on Java + Groovy + JDBC.
What is ExecutionContext?
The central per-request object. Provides access to all facades (entity, service, screen). Created fresh for each HTTP request and destroyed after.
What is a Facade?
A simplified API hiding complex internal logic. EntityFacade hides all JDBC/SQL. ServiceFacade hides service discovery and transactions. Created once at boot, shared across all requests.
Does Moqui use JDBC?
Yes, internally through the Entity Engine. Developers never write raw JDBC — EntityFacade generates all SQL and manages connections via HikariCP pool.
What is the Entity Engine?
Moqui's ORM. Converts entity XML definitions into EntityDefinition objects, generates SQL tables via ./gradlew load, and handles all CRUD operations at runtime.
What is a view-entity?
The XML equivalent of a SQL VIEW. Defines joins between entities, selects specific fields, applies conditions — all in XML without writing SQL.
What is entity-auto service?
Adarsh's Auto-generated CRUD services. Call create#party.Party without writing any service code — Moqui generates the INSERT logic automatically.
What is SECA?
Service Event Condition Action — trigger one service automatically when another runs. Like database triggers, but at the service level.

One-Line Definitions (Quick Reference)

MNode
Moqui's own fast in-memory XML node class (not standard Java DOM). All XML lives as MNode after parsing.
XmlAction
Converts XML action tags (<entity-find>, <set>, <if>) into Groovy bytecode. The bridge between XML and execution.
ContextStack
A stack of Maps that holds all in-scope variables for a request. Reading goes top-to-bottom. Writing always goes to the top.
HikariCP
Connection pool used by Moqui. Pre-creates DB connections and reuses them. Faster than creating new connection per query.
Bitronix / JTA
Transaction manager. Ensures ACID compliance. Automatically wraps each service call in a transaction with rollback on error.
sequence-bank-size
Pre-fetches N primary key IDs from DB to avoid a DB hit on every single insert. Default: 50.
optimistic-lock
Prevents overwrites: checks lastUpdatedStamp before save. If record changed since you read it, throws error.
Party Model
Enterprise data model where Person and Organization both extend an abstract Party. Enables one entity (ACME Corp) to be both customer and supplier.
← Back to Portal