Entity Backing Bean

An EntityBackingBean is the backing bean for an entity type for managing and searching entities interactively. It uses JPA for persistence, and property annotations for entity presentation and query.

Persistence Annotation

For an entity type to be managed by JPA, it must be annotated by JPA standard. For example,

@Entity(name = "Employee")
@Table(name = "Employee")
public class Employee extends PersistenceEntityBase implements NormativeId {
	public enum Type {
		FULL_TIME,
		PART_TIME
	}
	
	private String name;
	private String nid; // employee id
	private Type type;
	private Date hiredDate;
  
	@Id
	@GeneratedValue(strategy=GenerationType.TABLE, generator="ExampleHR.EMP_IdGen")
	@TableGenerator(name="ExampleHR.EMP_IdGen", table="IdGen",
		pkColumnName="entityType", valueColumnName="idValue",
		pkColumnValue="ExampleHR.EMP", initialValue=1, allocationSize=1)
	)  
	public Long getId() {  
		return id;
	}
	
	@Column(nullable=false, length=30)
	public String getName() {
		return name;
	}
  
	public void setName(String name) {
		this.name = name;
	}
  
	@Column(nullable=false, unique=true, length=10)
	public String getNid() {
    	return nid;
	}
  
	public void setNid(String nid) {
    	this.nid = nid;
	}

	@Column(nullable=false)
	@Enumerated(value=EnumType.ORDINAL)
	public Type getType() {
		return type;
	}

	public void setType(Type type) {
		this.type = type;
	}

	@Column(nullable=false)
	@Temporal(value=TemporalType.DATE)
	public Date getHiredDate() {
		return hiredDate;
	}

	public void setHiredDate(Date hiredDate) {
		this.hiredDate = hiredDate;
	}
  
	public String toString() {
		return nid + "/" + name;
	}
}
Id table generator is recommended since it is portable across all types of databases. The IdGen table has been created in every persistence unit.

For an entity type to be managed by Cmobilecom AF for entity creation, view and query, its EntityBackingBean must be defined. For example,


public class EmployeeBean extends EntityBackingBean<Employee> {

	@Properties({
		@Property(name="nid", view={ViewType.ALL}),
		@Property(name="name", view={ViewType.ALL}),
		@Property(name="hiredDate", view={ViewType.ALL}),
		@Property(name="type", view={ViewType.ALL},
				renderStyle=@RenderStyleDef(style=RenderStyle.SELECT_ONE_MENU))
	})
	public boolean hasPropertyAnnotations() {
		return true; 
	}
	
	@Override
	public List<SelectItem> getPropertySelectItems(
			EntityProperty<Employee> property) throws SystemException {
		ChoiceType choiceType;
		String propertyName = property.getName();

		if (propertyName.equals("type"))
			choiceType = HrModule.EMPLOYEE_TYPE;
		else
			return super.getPropertySelectItems(property);

		return SelectItemListProvider.getInstance(null).
			getSelectItems(choiceType, property);
	}
}
EntityBackingBean has built-in functionalities of entity persistence, query, and presentation using entity and property annotations. see Property Annotations.

Header and Footer Menu

By default an EntityBackingBean has create command for creating entity, search command for query, help command for context help, print command for print friendly, edit command for editing, applyChange command for saving changes.

More menu nodes can be added if needed. The following example, add menu node(Approve) in view mode.


	@Override
	protected void addMenuNodes(ModeType modeType) throws SystemException {
		super.addMenuNodes(modeType);
		
		if (modeType.equals(ModeType.VIEW)) {   		
  			AccessControlAccessor acAccessor = AccessControlAccessor.getInstance();
  	  		User currentUser = this.getAuthenticatedUser();	  
  	  
  	  		if (acAccessor.isUserHasPermission(currentUser, "ExampleHR", "ApproveEC")) {
   	  			MenuBean menuBean = getMenuBean("Approve", false);
  	  			if (menuBean != null) {
  	  				MenuNode approveMenuNode = new MenuNode(menuBean,  
  	  					"Approve", RenderStyle.COMMAND_BUTTON);
  	  				approveMenuNode.setIcon(MenuNode.UI_ICON_CHECK);
  	  				menuBean.add(approveMenuNode); 
  	  			}
			}
		}
	}
Override clickMenuNode() to handle the actions of the menu nodes.

	@Override
	public PageNavigation clickMenuNode(MenuNode menuNode) throws SystemException {
		String command = menuNode.getCommand();
     
		if (command.equals(COMMAND_APPROVE)) { 	    	
			// Approve command is clicked
		}
    
		return super.clickMenuNode(menuNode);
	}
Override header or footer MenuViewConfig to show/hide commands and specify which menu nodes are shown in header or footer menu.

	@Override
	protected MenuViewConfig getHeaderMenuViewConfig() {
		MenuViewConfig viewConfig = MenuViewConfig(MenuViewConfig.MenuStyle.LIST, RenderStyle.COMMAND_LINK, true);
		// show some menu nodes
		viewConfig.setMenuNodeToShow(...);
  	
		//or hide some menu nodes
		viewConfig.setMenuNodeToHide(...);
  	
		return viewConfig;
	}
	
	@Override
	protected MenuViewConfig getFooterMenuViewConfig() {
		MenuViewConfig viewConfig = MenuViewConfig(MenuViewConfig.MenuStyle.LIST, RenderStyle.COMMAND_BUTTON, true);
		// show some menu nodes
		viewConfig.setMenuNodeToShow(...);
  	
		//or hide some menu nodes
		viewConfig.setMenuNodeToHide(...);
  	
		return viewConfig;
	}
Another way to specify whether a command is supported, override the isCommandSupported(...) method. If a command is not supported, it will not be in header or footer menu.

  	@Override
	protected boolean isCommandSupported(PersistenceDataBackingBean<T> backingBean, String command) throws SystemException {
	
	}

Entity Type Context Menu

By default, an entity type has a context menu including create, import and query. To add more menu nodes,

	@Override
	public void addContextMenuNodes(TypedMenuNodeContextMenuBean menuBean) throws SystemException {
		super.addContextMenuNodes(menuBean);
  	
		// add more menu nodes
	}
Override clickContextMenuNode() to handle the actions of context menu nodes:

	@Override
	public PageNavigation clickContextMenuNode(MenuNode menuNode) throws SystemException {
		String command = menuNode.getCommand();
		if (command.equals("aCommand")) {
 			// handle action
		}
		
		return super.clickContextMenuNode(menuNode);
	}

Progress Bar

The action of a MenuNode can be a long-running task. A progress bar is the user-friendly way to show that an action is being executed and the UI is blocked until the task is completed.

Deleting all the entities of all pages can be a long time task, so progress bar is automatically enabled.

A default progress bar will be enabled if the menu node is set to show progress bar.

	MenuNode menuNode = new MenuNode(...);
	menuNode.setShowProgress(true);
The following method can be overridden to customize progress bar. Return null if progress bar is disabled for the menu node.

	@Override
	public ProgressDescriptor getProgressDescriptor(PersistenceDataBackingBean<T> backingBean, MenuNode menuNode) throws SystemException {

	}

Handle Ajax Behavior Events

Handle property ajax behavior event of the backing bean.

	@Override
	public PageNavigation handlePartialBehaviorEvent(PartialBehaviorEvent event, PersistenceDataBackingBean<T> backingBean,
  		T entity, EntityProperty<T> property) throws SystemException {
  	
	  	if (property.getName().equals("foo") && 
	  		event.getPartialBehavior().isValueChange()) {
			// handle event
			return null;
	  	}
	  	
		return super.handlePartialBehaviorEvent(event, backingBean, entity, property);
	}
  
Handle property ajax behavior event of the inputDataBean of a menu node. A menu node can have an EntityBackingBean for user to input data as arguments for the command, and the input data EntityBackingBean supports ajax behaviors for its properties.

	@Override
	public <M extends PersistenceEntity> PageNavigation handlePartialBehaviorEvent(
  		PartialBehaviorEvent event, MenuNode menuNode, EntityBackingBean<M> inputDataBackingBean, 
		EntityProperty<M> property) throws SystemException {
	  	
	}

Entity Fetch Graph

An entity type may define some properties and associated entities as lazy. An EntityFetchGraph defines the entities and properties to be fetched when retrieving an entity or a list of entities from persistence. For example, to define a fetch graph for showing an ExpenseClaim, override the following method in its EntityBackingBean:
  
	@Override
	protected EntityFetchGraph<ExpenseClaim> getEntityFetchGraph(ExpenseClaim entity) {
		EntityFetchGraph<ExpenseClaim> fetchGraph = super.getEntityFetchGraph(entity);
		
		fetchGraph.addProperty("expenseClaimItems", JoinType.LEFT);
		fetchGraph.addPropertyPath("employee.address", JoinType.LEFT);
		
		return fetchGraph;
	}
To define a fetch graph for showing a list of ExpenseClaim(s), override the following method in its EntityBackingBean:

	@Override
	protected EntityFetchGraph<ExpenseClaim> getEntityFetchGraph(EntityListBackingBean<xpenseClaim> entityListBackingBean) {
		EntityFetchGraph<ExpenseClaim> fetchGraph = super.getEntityFetchGraph(entityListBackingBean);
		
		fetchGraph.addProperty("employee", JoinType.INNER);
		return fetchGraph;
	}
	

Form Bean Properties

The value of a form bean property is an entity or a list of entities, and they are backed by EntityBackingBean and EntityListBackingBean respectively. So the value of a form bean property can be managed inside its parent enclosing bean. Form bean properties are annotated with type EntityFormBeanProperty.class. For example,

@Properties({
    @Property(name=ExpenseClaim.PROPERTY_EXPENSE_CLAIM_ITEMS, 
    	entityPropertyType=EntityFormBeanProperty.class,
    	nullAsDeleteProperties={ExpenseClaimItem.PROPERTY_DATE},
        view={ViewType.ENTITY})
})        
A form bean viewConfig can be set as a nested ViewConfig of its parent bean's ViewConfig.

ViewConfig

An EntityViewConfig can be provided when creating an EntityBackingBean, and it can be updated during bean initialization.

	@Override
	protected EntityViewConfig buildViewConfig(T entity) throws SystemException {
		EntityViewConfig viewConfig = super.buildViewConfig(entity);
		viewConfig.setPropertiesToHide(...);
		
		return viewConfig;
	}
An EntityListViewConfig can be provided when creating an EntityListBackingBean, and it can be updated during bean initialization.

	@Override
	protected EntityListViewConfig buildEntityListViewConfig(EntityListBackingBean<T> entityListBackingBean, 
  		EntityListViewConfig viewConfig) throws SystemException {
  		viewConfig = super.buildEntityListViewConfig(entityListBackingBean, viewConfig);
  		viewConfig.setPropertiesToShow(...);
  		
  		return viewConfig;
	}

Property Select Items

For a property whose render style is selecting one or many from a list of select items, its EntityBackingBean needs to provide the select items that can be static or dynamic. Dynamic select items can not be cached.

Get property select items that is static and can be cached.


	@Override
	public List<SelectItem> getPropertySelectItems(EntityProperty<T> property) throws SystemException {
		String propertyName = property.getName();
		if (propertyName.equals("type")) {
			...
		}
			
		return super.getPropertySelectItems(property);
	}
Get property dynamic select items that can not be cached.

	@Properties({
		@Property(name="type", view={ViewType.ALL},
			renderStyle=@RenderStyleDef(style=RenderStyle.SELECT_ONE_MENU, dynamicSelectItems=true))
	})

	@Override
	public List<SelectItem> getDynamicSelectItems(PersistenceDataBackingBean<T> backingBean, 
		T entity, EntityProperty<T> property) throws SystemException {
		String propertyName = property.getName();
		if (propertyName.equals("type")) {
			...
		}
		
		return super.getDynamicSelectItems(backingBean, entity, property);
	}
Note that the values of SelectItems must be of String type. The string value will be converted to its property type when updating property values(Model Update). Refer to SelectItemListProvider class for methods to create SelectItems from various data values.

Property Dynamic RenderStyle

When an EntityProperty is created, its render style needs to be specified. But if its render style is dynamic and can be different from entity to entity, then its EntityBackingBean needs to override getDynamicRenderStyle(...) method:

	@Properties({
		@Property(name="type", view={ViewType.ALL},
			dynamicRenderStyle=true,
			renderStyle=@RenderStyleDef(style=RenderStyle.SELECT_ONE_MENU))
	})

	@Override
	public RenderStyle getDynamicRenderStyle(PersistenceDataBackingBean<T> backingBean, 
		T entity, EntityProperty<T> property) throws SystemException {
		
		String propertyName = property.getName();
		if (propertyName.equals("type")) {
			...
		}
		
		return super.getDynamicRenderStyle(backingBean, entity, property);
	}

Property Dynamic Value

A property value can be dynamic, which means that its value is different than the property value read from entity.

	@Properties({
		@Property(name="type", view={ViewType.ALL},
			dynamicValue=true)
	})
	
	@Override
	public Object getPropertyDynamicValue(PersistenceDataBackingBean<T> backingBean, 
		T entity, EntityProperty<T> property) throws SystemException {
		
		String propertyName = property.getName();
		if (propertyName.equals("type")) {
			...
		}		
		return super.getPropertyDynamicValue(backingBean, entity, property); 
	}

Entity Validation

An entity can be validated before created or updated in persistence. In addition to value validation, entity validation can be any logic. For example, calculate total, change the values of related entities, etc. Note that entity unique key restrictions and property values have been validated by their annotations.

	@Override
	public void validate() throws SystemException {
		super.validate();
		...
	}
In query view, the validate() method is also called before search.

See Validation.

Transaction Interceptors

Transaction Interceptors are called during commiting entity creation, changes, or deletion in persistence. All the changes to any entities in the interceptors will be in the same transaction.

preCreate: called before creating the entity in persistence.


	protected boolean preCreate(T entity, ActionDescriptor ad, 
  		PersistenceEntityManager peManager) throws SystemException {
	}
postCreate: called after creating the entity in persistence but before committed.
 
	protected void postCreate(T entity, ActionDescriptor ad, 
  		PersistenceEntityManager peManager)throws SystemException {

	}
preApplyChange: called before saving changes of the entity in persistence.

	protected T preApplyChange(T entity, ActionDescriptor ad, 
  		PersistenceEntityManager peManager)throws SystemException {  	
	}
postApplyChange: called after saving changes of the entity in persistence but before committed.
  
	protected void postApplyChange(T entity, ActionDescriptor ad, 
  		PersistenceEntityManager peManager) throws SystemException {
	}
preDelete: called before deleting the entity in persistence.

	@Override
	protected boolean preDelete(T entity, ActionDescriptor ad, 
  		PersistenceEntityManager peManager)throws SystemException {
  		
	}
postDelete: called after deleting the entity in persistence but before committed.

	@Override
	protected void postDelete(T entity, ActionDescriptor ad, 
  		PersistenceEntityManager peManager)throws SystemException {

	}

Statistics Properties

A list of statistics properties can be defined that will be computed in the list view. The most common statistics function is sum and average. The statistics row will be shown at the bottom of entity list.

	@Override
	public StatisticsProperty[] getStatisticsProperties() {
		return new StatisticsProperty[]{
			new StatisticsProperty(ExpenseClaimItem.PROPERTY_EXPENSE, Aggregate.SUM)			
		}; 
	}

Entity Property Layout

The layout of entity properties is specified in EntityBackingBean viewConfig. For example, entityViewConfig.setLayoutType(LayoutType.FLOW);

Layout type can be layout code, table, flow, tab view, list view. The default layout is table with property name column and property value column if layout code is null. Newspaper columns is supported for table view.

If layoutType is null without form design, layout mode can be table or list view for mobile, but always table for desktop. List view is responsive with name and value in one row for each property. Users can select layoutMode to display an entity in different layouts.

For tab view, top-level properties should be property groups or form bean properties. For layout code, form designs allow end users to customize/create layouts. But if form design is not supported, override getLayoutCode() to provide the layout code. Layout code is a piece of HTML code that can embed expressions. For example,


	@Override
	public String getLayoutCode() throws SystemException {
		return "<h1>Expense Claim</h1>#{bundle.Employee}: #{employee}<br/>#{OBJECT:expenseClaimItems}";
	}

Newspaper Columns

For table view of properties, the number of newspaper columns is the number of properties to show per row. default is 1.

For example, 9 properties: 1, 2, 3, 4, 5, 6, 7, 8, 9. If newspaper columns is 1: one property per row. If newspaper columns is 2(two properties per row), the 9 properties will shown as following:


horizontal orientation:
  1  2
  3  4
  5  6
  7  8
  9
vertical orientation:
  1  6
  2  7
  3  8
  4  9
  5   

Entity Import/Export as XML

See Entity Export/Import for detail.