Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

Table of Contents

...

1.

...

What

...

is

...

custom

...

method?

...

You

...

can

...

create

...

custom

...

method

...

and

...

attach

...

it

...

to

...

defined

...

model

...

or

...

view.

...

Using

...

this

...

elements,

...

you

...

can

...

connect

...

defined

...

xml

...

to

...

JAVA

...

code.

...

To

...

create

...

custom

...

method

...

first

...

you

...

must

...

create

...

service,

...

then

...

implement

...

one

...

or

...

more

...

custom

...

methods.

...

Then

...

you

...

insert

...

reference

...

to

...

created

...

method

...

in

...

xml

...

files.

...

2.

...

Create

...

custom

...

methods

...

service

...

2.1.

...

service

...

structure

...

Custom

...

methods

...

service

...

is

...

basically normal

...

JAVA

...

class.

...

Only

...

additional

...

element

...

is

...

Spring

...

'@Service'

...

annotation.

...

Code Block
themeEclipse
languagejava
linenumberstrue
import org.springframework.stereotype.Service;

@Service
public class ClassName {

       // CLASS BODY

}

{code}

h4. 

2.2.

...

additional

...

services

...

access

...

In

...

created

...

service

...

you

...

can

...

access

...

many

...

additional

...

services

...

that

...

helps

...

you

...

manipulate

...

data

...

or

...

view.

...

Access

...

to

...

outside

...

service

...

are

...

made

...

by

...

Spring

...

'@Autowired'

...

annotation.

...

Code Block
themeEclipse
languagejava
linenumberstrue
import org.springframework.beans.factory.annotation.Autowired;

...

    @Autowired
    private ServiceType setviceName;

{code}

h4. 

2.3.

...

additional

...

services

...

2.3.1.

...

DataDefinitionService

...

This

...

service

...

provides

...

both

...

information

...

about

...

entities

...

model

...

and

...

access

...

to

...

database

...

operations.

...

2.3.2.

...

TranslationService

...

Service

...

used

...

to

...

execute

...

translation

...

to

...

users

...

language.

...

2.3.3.

...

SecurityService

...

This

...

service

...

allow

...

you

...

to

...

access

...

informations

...

about

...

current

...

user.

...

3.

...

custom

...

methods

...

Anchor
customValidators
customValidators

3.1.

...

Custom

...

validators

...

Custom

...

validator

...

is

...

used

...

by

...

model

...

to

...

validate

...

entities.

...

Custom

...

validator

...

function

...

has

...

structure:

...

Code Block
themeEclipse
languagejava
linenumberstrue
public boolean validatorMethodName(final DataDefinition dataDefinition, final Entity entity) {

        // VALIDATOR METHOD BODY

}

{code}
Where
* validatorMethodName - name of validator method
* dataDefinition - dataDefinition of validated entity
* entity - entity to validate

This method should return true if validation was successfull and false otherwise.

When validation was unsuccessfull you can also add validation message to entity field using construction:

{code}
   

Where

  • validatorMethodName - name of validator method
  • dataDefinition - dataDefinition of validated entity
  • entity - entity to validate

This method should return true if validation was successfull and false otherwise.

When validation was unsuccessfull you can also add validation message to entity field using construction:

Code Block
themeEclipse
languagejava
linenumberstrue
   entity.addError(dataDefinition.getField("fieldName"), "validationMessage");
{code}
Where
* fieldName - name of entity model field
* validationMessage - validation message

To attach created validator method to model xml file see ['model custom validators'|QCDMESDOC:Model Definition Overview#customValidators] section.

{anchor:modelHooks}

h4. 2.2. Model hooks

Model hooks are methods that is executed on specific model actions (defined in xml file). Model hook method has structure:

{code}

Where

  • fieldName - name of entity model field
  • validationMessage - validation message

To attach created validator method to model xml file see 'model custom validators' section.

If you need some sample code see Custom validator example in Examples section

Anchor
modelHooks
modelHooks

2.2. Model hooks

Model hooks are methods that is executed on specific model actions (defined in xml file). Model hook method has structure:

Code Block
themeEclipse
languagejava
linenumberstrue
public void modelHookMethodName(final DataDefinition dataDefinition, final Entity entity) {

        // MODEL HOOK BODY

}

{code}
Where
* modelHookMethodName - name of model hook method
* dataDefinition - dataDefinition of hook event entity
* entity - hook event entity

To attach created model hook method to model xml file see ['custom model event hooks'|QCDMESDOC:Model Definition Overview#customEventHooks] section.

{anchor:viewHooks}

h4. 2.3. View hooks

View hooks are methods that is executed always where request is send to server. View hook method has structure:

{code}

Where

  • modelHookMethodName - name of model hook method
  • dataDefinition - data definition of hook event entity
  • entity - hook event entity

To attach created model hook method to model xml file see 'custom model event hooks' section.

If you need some sample code see Model hook example in Examples section

Anchor
viewHooks
viewHooks

2.3. View hooks

View hooks are methods that is executed always where request is send to server. View hook method has structure:

Code Block
themeEclipse
languagejava
linenumberstrue
public void viewHookMethodName(final ViewDefinitionState state, final Locale locale) {

        // VIEW HOOK BODY

}

{code}
Where
* viewHookMethodName - name of view hook method
* state - view state
* locale - users locale

To attach created view hook method to view xml file see ['view hooks'|QCDMESDOC:Hooks and Listeners#viewHooks] section.

{anchor:viewListeners}

h4. 2.4. View listeners

View listeners are methods that is executed when specified event is fired. View listener method has structure:

{code}
public void 

Where

  • viewHookMethodName - name of view hook method
  • state - view state

To attach created view hook method to view xml file see 'view hooks' section.

If you need some sample code see View hook example in Examples section.

Anchor
viewListeners
viewListeners

2.4. View listeners

View listeners are methods that is executed when specified event is fired. View listener method has structure:

Code Block
themeEclipse
languagejava
linenumberstrue
public void viewListenerMethodName(final ViewDefinitionState state, final ComponentState componentState, final String[] args) {

        // VIEW LISTENER BODY

}

{code}
Where
* viewListenerMethodName - name of view listener method
* state - view state
* componentState - component that fired event
* args - array of event arguments

To attach created view listener method to view xml file see ['view listeners'|QCDMESDOC:Hooks and Listeners#viewListeners] section.

h3. 3. Example


h4. 3.1 Custom validator example:
{code}    public boolean checkIfOrderHasTechnology(final DataDefinition dataDefinition, final Entity entity) {
        Entity order = entity.getBelongsToField("order");

        if (order == null

Where

  • viewListenerMethodName - name of view listener method
  • state - view state
  • componentState - component that fired event
  • args - array of event arguments

To attach created view listener method to view xml file see 'view listeners' section.

If you need some sample code see View listener example in Examples section.

Anchor
rowStyleResolvers
rowStyleResolvers

2.5. Row style resolvers

(Grid's) Row style resolvers returns set of CSS clas names for given row entity. You can use them to mark specified grid rows, e.g. whith negative balance of some arbitrary values. 
Resolver method is invoked for each of row entity.

Code Block
themeEclipse
languagejava
linenumberstrue
public Set<String> rowStyleResolverName(final Entity rowEntity) {

        // ROW STYLE returnRESOLVER true;BODY

       }

        if (order.getField("technology") == null) {
            entity.addError(dataDefinition.getField("order"), "products.validate.global.error.orderMustHaveTechnology");
            return false;
        } else {
            return true;
        }
    }{code}

h4. 3.2 Model hook example:

(this particular example is used within the <onSave> tag:
    public void fillOrderDatesAndWorkers(final DataDefinition dataDefinition, final Entity entity) {
        if (("02inProgress".equals(entity.getField("state")) || "03done".equals(entity.getField("state")))
                && entity.getField("effectiveDateFrom") == null) }

Where

  • rowStyleResolverName - arbitrary name of resolver method
  • rowEntity - entity which will be shown in row

Return values (CSS classes) currently supported by Qcadoo Framework:

CSS class nameConstantDescription
redBgRowStyle.RED_BACKGROUNDset row background to red
boldFontRowStyle.BOLD_FONTset row font weight to bold
yellowBgRowStyle.YELLOW_BACKGROUNDset row background to yellow
brownBgRowStyle.BROWN_BACKGROUND

set row background to brown

blueBgRowStyle.BLUE_BACKGROUNDset row background to blue
greenBgRowStyle.GREEN_BACKGROUNDset row background to green
Info

Prefer constants over CSS class name literals. This will help you avoid many mistakes and keep your code easier to maintain.

Info

You can also create infinity number of your own, custom row styles - see Customizing GUI appearance section.

To see how to bind created resolver method with view component go to 'row style resolvers' in 'Hook an Listeners' section.

If you need some sample code see Row style resolver example in Examples section.

Anchor
criteriaModifier
criteriaModifier

2.6. Criteria modifier

(Grid's) Criteria modifier allow you to modify state of the SearchCriteriaBuilder used by view component to fetch row entities.

Code Block
themeEclipse
languagejava
linenumberstrue
public void criteriaModifierName(final SearchCriteriaBuilder searchCriteriaBuilder) {

        // CRITERIA MODIFIER BODY

}

Where

  • criteriaModifierName - arbitrary name of modifier method
  • searchCriteriaBuilder - criteria builder used by component

There is also second version of criteria modifier method that you can define:

Code Block
themeEclipse
languagejava
linenumberstrue
public void criteriaModifierName(final SearchCriteriaBuilder searchCriteriaBuilder, final FilterValueHolder filterValueHolder ) {

        // CRITERIA  entity.setField("effectiveDateFrom", new Date());
            entity.setField("startWorker", securityService.getCurrentUserName());
        }
        if ("03done".equals(entity.getField("state")) && entity.getField("effectiveDateTo") == null) {
   MODIFIER BODY
}

Where

  • criteriaModifierName - arbitrary name of modifier method
  • searchCriteriaBuilder - criteria builder used by component
  • filterValueHolder - criteria value passed from before render hook. 

To set FilterValueHolder you have to get it from LookupComponent in before render hook, modify it and set it again

Code Block
themeEclipse
languagejava
linenumberstrue
public void beforeRenderHook(final ViewDefinitionState viewDefinitionState) {
	LookupComponent lookup= (LookupComponent) 
					viewDefinitionState.getComponentByReference("lookupReference");
	FilterValueHolder holder = lookup.getFilterValue();
	holder.put("key", "value");
	lookup.setFilterValue(holder);
}

To see how to bind modifier method with view component go to 'criteria modifiers' in 'Hook an Listeners' section.

If you need some sample code see Criteria modifier example in Examples section.

Anchor
examples
examples

3. Examples

Anchor
customValidatorExample
customValidatorExample

3.1 Custom validator example

Code Block
themeEclipse
languagejava
linenumberstrue
    public boolean checkIfOrderHasTechnology(final DataDefinition dataDefinition, final Entity entity) {
        Entity order = entity.getBelongsToField("order");

        if (order == null) {
            return true;
        }

        if (order.getField("technology") == null) {
            entity.addError(dataDefinition.getField("order"), "products.validate.global.error.orderMustHaveTechnology");
            return false;
        } else {
            return true;
        }
    }

Anchor
modelHookExample
modelHookExample

3.2 Model hook example:

(this particular example is used within the <onSave> tag:

Code Block
    public void fillOrderDatesAndWorkers(final DataDefinition dataDefinition, final Entity entity) {
        if (("02inProgress".equals(entity.getField("state")) || "03done".equals(entity.getField("state")))
                && entity.getField("effectiveDateFrom") == null) {
            entity.setField("effectiveDateFrom", new Date());
            entity.setField("startWorker", securityService.getCurrentUserName());
        }
        if ("03done".equals(entity.getField("state")) && entity.getField("effectiveDateTo") == null) {
            entity.setField("effectiveDateTo", new Date());
            entity.setField("endWorker", securityService.getCurrentUserName());
        }
    }

Anchor
viewHookExample
viewHookExample

3.3 View hook (preRender) example

Code Block
themeEclipse
languagejava
linenumberstrue
   public void checkIfCommentIsRequiredBasedOnResult(final ViewDefinitionState state) {
        FieldComponentState comment = (FieldComponentState) state.getComponentByReference("comment");

        FieldComponentState controlResult = (FieldComponentState) state.getComponentByReference("controlResult");

        if (controlResult != null && controlResult.getFieldValue() != null && "03objection".equals(controlResult.getFieldValue())) {
            comment.setRequired(true);
            comment.requestComponentUpdateState();
        } else {
            comment.setRequired(false);
        }

    }

Anchor
viewListenerExample
viewListenerExample

3.3 View listener hook example

Code Block
themeEclipse
languagejava
linenumberstrue
    public void checkAcceptedDefectsQuantity(final ViewDefinitionState viewDefinitionState, final ComponentState state,
            final String[] args) {
        if (!(state instanceof FieldComponentState)) {
            throw new IllegalStateException("component is not input");
        }

        FieldComponentState acceptedDefectsQuantity = (FieldComponentState) state;

        FieldComponentState comment = (FieldComponentState) viewDefinitionState.getComponentByReference("comment");

        if (acceptedDefectsQuantity.getFieldValue() != null) {
            if (isNumber(acceptedDefectsQuantity.getFieldValue().toString())
                    && (new BigDecimal(acceptedDefectsQuantity.getFieldValue().toString())).compareTo(BigDecimal.ZERO) > 0) {
                comment.setRequired(true);
            } else {
                comment.setRequired(false);
            }
        }
    }

Anchor
rowStyleResolverExample
rowStyleResolverExample

3.4 Row style resolver example

Code Block
themeEclipse
languagejava
linenumberstrue
    public Set<String> productsListRowStyleResolver(final Entity product) {
        final Set<String> entityStyles = Sets.newHashSet();
        final String materialType = product.getStringField(ProductFields.GLOBAL_TYPE_OF_MATERIAL);

        if ("04waste".equals(materialType)) {
            entityStyles.add(RowStyle.RED_BACKGROUND);
        }

        if (StringUtils.isBlank(product.getStringField(ProductFields.EAN))) {
            entityStyles.add(RowStyle.BOLD_FONT);
        }
        return entityStyles;
    }

Anchor
criteriaModifierExample
criteriaModifierExample

3.5 Criteria modifier example

  1. Single parameter example:

    Code Block
    themeEclipse
    languagejava
    linenumberstrue
    public void filterOutNotBelongingToCurrentUser(final SearchCriteriaBuilder scb) {
        scb.add(SearchRestrictions.eq("owner", securityService.getCurrentUserName()));
    }
  2. Context example: 
    Models:
    1. Shop
    2. Chain
    3. Industry
    Relations
    1. Shop hasMany Industries
    2. Chain hasMany Industries
    3. Shop belongsTo Chain
     

    Target: In industires lookup in shop details view show only industires that are in relation with chain of the shop. 

    Code Block
    themeEclipse
    languagehtml/xml
    linenumberstrue
    <view name="shopDetails" modelName="shop" ...>
         <component type="window" name="window">         

...

  1.   
    			...
               

...

  1. <component type="form" name="form" reference="form">
           

...

  1.      

...

  1.    

...

  1.  

...

  1.  

...

  1.  

...

  1.  ...
       

...

  1.  

...

  1.  

...

  1.  

...

  1.  

...

  1.  

...

  1.  

...

  1.  

...

  1.  

...

  1.          

...

  1. <component type="lookup" name="industry" reference="industryLookup" 
    								field="industries" defaultVisible="false" persistent="false" hasLabel="false">
          

...

  1.  

...

  1.  

...

  1.  

...

  1.  

...

  1.          

...

  1.  

...

  1.  

...

  1.  

...

  1.  

...

  1. .

...

  1. .

...

  1. .

...

  1. 
               

...

  1.              

...

  1.     <criteriaModifier 
    								class="com.qcadoo.sdt.basic.criteriaModifiers.ShopIndustryLookupCriteriaModifier"						   

...

  1.  
    								method="restrictIndustriesToChainContext" />
                

...

  1.         

...

  1. </component>
    					...
       

...

  1.   

...

  1.  

...

  1.  

...

  1.  

...

  1.  

...

  1.  

...

  1.  </component>
       

...

  1.  

...

  1.  </component>
        <hooks>
    		<beforeRender class="com.qcadoo.sdt.basic.hooks.view.ShopDetailsBeforeRenderService" 
    					method="setCriteriaModifierParameters"/>
        </hooks>
    </view>
    
    
    Code Block
    themeEclipse
    languagejava
    linenumberstrue
    @Service
    public 

...

  1. class 

...

  1. ShopDetailsBeforeRenderService {
    
        public void setCriteriaModifierParameters(final 

...

  1. ViewDefinitionState 

...

  1. state

...

  1. )

...

  1.  {
            LookupComponent industryLookup = 

...

  1. (LookupComponent) state.getComponentByReference("industryLookup");
            FormComponent form 

...

  1. = (

...

  1. FormComponent) state.getComponentByReference("form");
    
            

...

  1. Entity 

...

  1. shop = 

...

  1. form.getEntity();

...

  1. 
            if (

...

  1. shop.

...

  1. getId() != null) {
                

...

  1. Entity chain = shop.getBelongsToField(ShopFields.CHAIN_FIELD);
                FilterValueHolder holder = industryLookup.getFilterValue();
        

...

  1.         holder.put(ShopIndustryLookupCriteriaModifier.CHAIN_PARAMETER, chain.getId());
                

...

  1. industryLookup.

...

  1. setFilterValue(

...

  1. holder);
            }
        }
    

...

  1. }

     

    Code Block
    themeEclipse
    languagejava
    linenumberstrue
    @Service
    public class ShopIndustryLookupCriteriaModifier {
    
    	public static final String CHAIN_PARAMETER = "chain";
    	
    	private static final String CHAIN_REQUIRED = "Chain parameter is required";
    
    	public void restrictIndustriesToChainContext(final SearchCriteriaBuilder scb, final FilterValueHolder filterValue){
    		if(!filterValue.has(CHAIN_PARAMETER)){
    			throw new IllegalArgumentException(CHAIN_REQUIRED);
    		}
    		
    		Long chainId = filterValue.getLong(CHAIN_PARAMETER);
    		scb.createAlias(IndustryFields.CHAINS_FIELD, "c").add(SearchRestrictions.eq("c.id", chainId));
    	}
    }