General

This is the reference for the Enterprise Framework module. The goal of this document is to provide in-depth details on most aspects of the framework. The Groovydoc (Javadoc) API covers other details of the underlying classes, but this document explains the higher-level features and behavior.

For a high-level treatment of these features, see the User Guide.

Document Conventions

This document follows certain conventions as shown below:

  • Literal values

  • File/path names

  • Class names

  • Variables, fields or parameters

  • Method names

  • Groovy or java code

See Naming Conventions for details on how elements are named.

There are a number of diagrams in these documents. We follow the given conventions for these diagrams. Some colors and shapes are used to flag specific types of elements:

colorShapeConventions
Figure 1. Color and Shape Conventions

Document Layout

Most modules have 3 main sets of documents:

  • Guide - General overview and key concepts document.

  • Reference - In depth reference for APIs, Domains, etc.

  • Groovydoc - The generated Groovydoc (Javadoc) from the source code.

The intent of the guide is to give you a general overview of feature, but not overwhelm you with details of the implementation. The reference documentation will explain most key fields, API calls and options. The guide generally has many links into the reference documentation.

Dashboards are fairly complex. To manage this in the documents, we use the guide for concept introduction and sometime simple examples. The reference document will explain all of the activities, events and scan actions for the dashboard. Each module will have additional activities, events and scan actions. These will be documented in a similar way:

dashboardDocuments
Figure 2. Dashboard Documents - MES Core Example

Folder Conventions

For the most part, your application should be free to use most Micronaut-supported folder conventions. This is pretty open, so the framework and application modules that we develop will follow a specific folder layout for common artifacts.

Each major package for an application module should be organized like this:

  • product (Product Definition package for the MES Core module)

    • controller

    • domain

    • page (GEB GUI Test Pages - in src/test/groovy folder)

    • service

The folder layouts we will use are for the src/main/groovy source folder looks something like this under the org.simplemes.eframe package:

  • application (startup and common pages "/")

    • controller

    • domain

    • service

  • controller (controller support classes)

  • custom

    • controller

    • domain

  • domain (domain support classes)

  • misc

  • security

    • controller

    • domain

    • service

  • system

  • test

  • web

    • request

    • view

    • builder

    • widget

Domain

There are many support utilities for Domain classes used to help developers within the framework. These are defined in the API Documentation, but key classes, fields and methods are discussed here.

fieldOrder

Field Ordering

Frequently, the framework features will need to list or display your domain fields in a logical order. Framework markers such as [efShow] will show the fields in any order you like, but you would have to update the [efShow] marker for every new field added to the domain class. To simplify this maintenance task, the framework supports an optional fieldOrder static variable in domain classes.

Philosophical Discussion Ahead!

Field ordering is not traditionally part of a domain class’s definition. Following the 'Don’t Repeat Yourself' philosophy, a central place to store the field ordering 'hints' is needed. We chose the domain class. This is optional. If you don’t want to embed field ordering in your domain classes, then you can specify the field ordering on the respective [efShow], [efCreate] and [efEdit] markers in your .ftl files. This means updating 3 files whenever you add a new field to a domain class. This is your choice.

The field ordering can also be configured by a user to add Field Extension GUI, move core fields and remove core fields from the GUI.

Simple Ordering

Most simple domain classes will use just a simple list of fields in the order to be displayed. Any fields not listed will not be displayed.

Domain Class with fieldOrder
class Product {
  String product
  Status status
  String description
  BigDecimal lotSize

  static fieldOrder = ['product', 'status', 'lotSize', 'description']
}

The framework marker [efShow] can then be used to display these fields in the order you need:

ftl Page Use
<@efShow fields="order,product,qtyToBuild,qtyDone,dateCompleted"/>

Now, you can add a new field to the domain without updating your .ftl files. You only have to remember to add the new field(s) to the fieldOrder variable. See the Testing fieldOrder Variable for details on how you can verify that all fields are listed in the fieldOrder variable.

Grouping of Field (Panels)

Simple grouping of fields is possible when you use a 'group:name' value in your fieldOrder variable. An example is shown below, with the fieldOrder setting needed for it.

Show
Domain Class with Grouping
class Product {
  String name
  String title
  BigDecimal qty
  Integer count
  Boolean enabled
  Date dateTime
  DateOnly dueDate
  String notes

  static fieldOrder = ['name', 'title', 'qty', 'count', 'enabled', 'dueDate', 'dateTime',
                       'group:details', 'notes']
}

In the [efShow] marker, this will create two tabbed panels: 'Main' and 'Details'. The titles for these tabs will be pulled from the messages.properties file entry as shown below:

messages.properties (Framework Tab Names)
custom.panel.label=Custom
details.panel.label=Details
main.panel.label=Main

Any other panel labels will need to be defined in your messages.properties file.

By default, if any group is defined, all fields up to the first 'group' entry will be placed in a panel titled 'Main'. You can change the label for this first panel as you wish by specifying it in the fieldOrder variable:

class Product {
  static fieldOrder = ['group:first', 'product', 'status', 'lotSize',
                       'group:details.label', 'assemblyData', 'routing']
}

If the 'first' panel has no localized label, the text 'first' will be displayed. This allows custom panels to use the label as-is.

Testing fieldOrder Variable

We recommend that you test to your domain class tests to ensure that all fields are accounted for in the fieldOrder variable. The helper class DomainTester tests the fieldOrder by default:

Example Domain Test
def "verify that user domain enforces constraints"() {
  expect: 'the constraints are enforced'
  DomainTester.test {
    domain Order
    requiredValues order: 'M1003', qty: 2.0       (1)
    maxSize 'order', FieldSizes.MAX_CODE_LENGTH   (2)
    maxSize 'password', 128
    notNullCheck 'userName'                       (3)
    notNullCheck 'password'
    notInFieldOrder (['authorities', 'password']) (4)
  }
}
1 Defines the required values for the domain record.
2 Verifies that the max length is enforced.
3 Verifies that null values are prevented.
4 Checks that the fieldOrder is defined correctly for the domain class. Verifies that all persistent fields are listed in the fieldOrder list.

You can also disable the fieldOrder check with the option 'fieldOrderCheck false'.

Initial Data Load

Initial data loading is one of the common setup needs for large applications. These applications usually have a number of status codes or numbering sequences that need some sort of initial values. If you don’t have some reasonable defaults, then your first-time customers may spend hours trying to configure your product. This will discourage most normal customers.

To trigger the initial data load on startup, you will need to add a method to your domain class. This method will be executed on application startup. The method should check for the existence of the record before attempting to create it. You should also minimize the logic to reduce startup time. Don’t add extensive or slow logic it you can avoid it.

Example Initial Data Load
static initialDataLoad() {
  if (!findByKey('2000')) {
    new SampleDomain(key: '2000', name: 'Ready').save()
  }

  if (!findByKey('2001')) {
    new SampleDomain(key: '2001', name: 'Done').save()
  }
}

GUI

Components CRUDTable

Services CRUDService

This section is the reference section for the GUI components used in the GUI sub-modules. These are Vue modules that are used by the GUIs to simplify GUI development.

CRUDTable

The CRUDTable component defines the initial CRUD table for most definition objects. This also provides the components needed to maintain these objects (add/edit/delete) and object-specific actions.

Properties

The main properties supported are:

Table 1. Parameters
Property Description

:columns

The array containing the columns to be displayed in the table (Required). Elements include: field, header, and sort (boolean).

:service

The name of the Javascript object that interfaces to the server-side logic (Required). This service must provide the CRUDService methods.

:domainClassName

The variable that will hold the qualified class name of the domain class being maintained by this table (Required).

Example - CRUDTable Usage
<template>
  <CrudTable :columns="columns" :service="service"
             :domainClassName="domainClassName"/>
</template>

<script>

import CrudTable from 'eframe-lib/components/web/CrudTable';
import FlexTypeService from 'eframe-lib/components/custom/flexType/FlexTypeService'

export default {
  components: {
    CrudTable
  },
  data() {
    return {
      columns: [
        {field: 'flexType', header: this.$t('label.flexType'), sort: true},
        {field: 'category', header: this.$t('label.category'), sort: true},
        {field: 'title', header: this.$t('label.title'), sort: true},
        {field: 'fieldSummary', header: this.$t('label.fields')},
      ],
      service: FlexTypeService,
      domainClassName: 'org.simplemes.eframe.custom.domain.FlexType',
    }
  },
}

</script>

CRUDService

These services are used by the CRUDTable component to maintain domain objects. The services must provide the list() and other methods to support creation/update of objects.

The CRUDTable component defines the initial CRUD table for most definition objects. This also provides the components needed to maintain these objects (add/edit/delete) and object-specific actions.

Methods

list()

The main properties supported are:

Table 2. Parameters
Argument Description

:options

The options supported are the standard options from the server-side BaseCrudController . This includes: rows, first, search, and sort (e.g. sort[fieldName]=asc} (Required).

:success

The Javascript function called when the list call returns with data (Required). This method is passed the results as a javascript object (from the JSON).

:error

The Javascript function called when a server-side error is returned (Optional). This method does NOT need to display any error message. That is handled by the caller (e.g. CRUDTable).

Example - CRUDService
import InMemoriam from 'in-memoriam';

const cache = new InMemoriam(50, 60000);

export default {
  // List for crud-style pages.
  list(options, successFunction, errorFunction) {
    const url = '/flexType/list';

    window.$page.vue.axios.get(url, {params: options}).then((response) => {
      if (successFunction) {
        successFunction(response.data)
      }
    }).catch((error) => {
      window.$page.handleError(error, url)
      if (errorFunction) {
        errorFunction(error, url)
      }
    })
  },
};
Table 3. Attributes

asciidoctor-version

2.0.10

safe-mode-name

unsafe

docdir

/home/runner/work/simplemes-core/simplemes-core/eframe/src/main/docs/asciidoc

docfile

/home/runner/work/simplemes-core/simplemes-core/eframe/src/main/docs/asciidoc/reference.adoc

doctype

book

imagesdir-build

images

imagesdir-src

images

imagesdir

images