Table of Contents

Filters

indexmenu_n_80

JPA criteria API is used for search entities from underlying database. JPA predicate has to be constructed for all supported filter properties. Predicate can be constructed two ways:

When no filter implementation is found for given filter property, then FilterNotSupportedException will be thrown. Filter builders (predicates) and all added filter properties have to be registered (constructed). Check for filter property is properly implemented is evaluated two ways:
  • By registered filter builders - filter key is used.
  • By filter definition (dto), if filter predicate is defined directly in service. Filter dto can define properties as fields or constants (see DataFilter generalization). Make sure all properties are defined in filter dto if services predicate is used - is required for check filter is supported.

Check for filter property is properly implemented can be turned off by configuration (e.g. before filter registration will be fixed).

All supported filters can be found in agenda (menu Setting→ Modules → Filters).

Filter can be used by authoritazation policy evaluator for securing data access.

Filter builder

The filter (FilterBuilder) is registered with the given key (FilterKey):

Evaluating of filters is done by FilterManager, which searches over the domain type during construction:

A filter must implement these methods:

The following ready-made abstract classes can be used for constructing a new filter:

Example filter

This example filter is meant for searching for identities by the username.

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Description;
import org.springframework.stereotype.Component;
 
import eu.bcvsolutions.idm.core.api.dto.filter.IdentityFilter;
import eu.bcvsolutions.idm.core.api.repository.filter.AbstractFilterBuilder;
import eu.bcvsolutions.idm.core.model.entity.IdmIdentity;
import eu.bcvsolutions.idm.core.model.entity.IdmIdentity_;
import eu.bcvsolutions.idm.core.model.repository.IdmIdentityRepository;
 
@Component
@Description("Filter by identity's username")
public class UsernameIdentityFilter extends AbstractFilterBuilder<IdmIdentity, IdentityFilter> {
 
	@Autowired
	public UsernameIdentityFilter(IdmIdentityRepository repository) {
		super(repository);
	}
 
	@Override
	public String getName() {
		return IdentityFilter.PARAMETER_USERNAME;
	}
 
	@Override
	public Predicate getPredicate(Root<IdmIdentity> root, AbstractQuery<?> query, CriteriaBuilder builder, IdentityFilter filter) {
		if (filter.getUsername() == null) {
			return null;
		}
		return builder.equal(root.get(IdmIdentity_.username), filter.getUsername());
	}
}

Example filter test

For every filter is highly recommended create also tests for filtering. There is example:

It is possible autowired filter as simple component/service and test behavior only specific filter. See test example.
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
 
import java.util.List;
 
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
 
import eu.bcvsolutions.idm.InitTestData;
import eu.bcvsolutions.idm.core.api.dto.IdmIdentityDto;
import eu.bcvsolutions.idm.core.api.dto.filter.IdmIdentityFilter;
import eu.bcvsolutions.idm.core.model.entity.IdmIdentity;
import eu.bcvsolutions.idm.test.api.AbstractIntegrationTest;
 
@Transactional
public class UsernameIdentityFilterTest extends AbstractIntegrationTest {
 
	@Autowired
	private UsernameIdentityFilter usernameIdentityFilter;
 
	@Test
	public void testFilteringFound() {
		String username = getHelper().createName();
		IdmIdentityDto identityOne = getHelper().createIdentity(username);
		IdmIdentityDto identityTwo = getHelper().createIdentity(getHelper().createName() + username + getHelper().createName());
		IdmIdentityDto identityThree = getHelper().createIdentity(getHelper().createName() + username + getHelper().createName());
 
		IdmIdentityFilter filter = new IdmIdentityFilter();
		filter.setUsername(username);
		List<IdmIdentity> identities = usernameIdentityFilter.find(filter, null).getContent();
 
		assertEquals(3, identities.size());
 
		IdmIdentity identity = identities.stream().filter(ident -> ident.getId().equals(identityOne.getId())).findFirst().get();
		assertNotNull(identity);
 
		identity = identities.stream().filter(ident -> ident.getId().equals(identityTwo.getId())).findFirst().get();
		assertNotNull(identity);
 
		identity = identities.stream().filter(ident -> ident.getId().equals(identityThree.getId())).findFirst().get();
		assertNotNull(identity);
	}
 
	@Test
	public void testFilteringNotFound() {
		String username = "usernameValue" + System.currentTimeMillis();
		getHelper().createIdentity(username);
		getHelper().createIdentity("123" + username + getHelper().createName());
		getHelper().createIdentity(getHelper().createName() + username + getHelper().createName());
 
		IdmIdentityFilter filter = new IdmIdentityFilter();
		filter.setUsername("username1Value"); // value is different than variable username
		List<IdmIdentity> identities = usernameIdentityFilter.find(filter, null).getContent();
 
		assertEquals(0, identities.size());
	}
}

Filter configuration

Filters are configurable thanks to interface Configurable via the standard application configuration.

There can be more filters with the same key ⇒ the one that is going to be used can be chosen via configuration item impl. Any module can be registered in this way and also the behaviour of the existing filters, which are implemented via interface FilterBuilder, can be changed. When filter override some existing filter, then default filter's module has to be used in configuration property.
Filter can be disabled - when filter is disabled and property is filled in filter (see getName method), then disjunction criteria is added ⇒ no data will be returned.

Implemented filters

UuidFilter

A generic filter for finding any entity (child of AbstractEntity) by its uuid (parameter in the filter - id).

UsernameIdentityFilter

Finding any entity by its username (parameter in the filter - username).

DefaultManagersFilter

Finding managers of the entity by the IR, tree structures and set guarantees. The manager is the identity which has its IR on an organizational structure component superordinate to a structure component of the subordinate's IR. The manager (guarantee) can also be configured directly to the IR.

Filter parameters

Configuration:

## identity filters
## managers by standard tree structure (manager will be found by contract on parent node)
idm.sec.core.filter.IdmIdentity.managersFor.impl=defaultManagersFilter

DefaultManagerContractBySubordinateContractFilter

@since 10.4.0

Find managers' contracts by subordinate contract. Finding managers' contracts by tree structures and set guarantees. The manager contract is on an organizational structure component superordinate to a structure component of the subordinate's contract. The manager (guarantee) can also be configured directly to the subordinate contract.

Filter parameters

Configuration:

## contract filters
## managers by standard tree structure (manager will be found by contract on parent node)
idm.sec.core.filter.IdmIdentityContract.managersByContract.impl=default-manager-contract-by-subordinate-contract-filter

DefaultSubordinatesFilter

Finding subordinates of the entity by the IR, tree structures and set guarantees. The subordinate is the identity which has its IR on an organizational structure component subordinate to a structure component of the manager's IR. The guarantee can also be configured directly to the IR.

Filter parameters

Configuration:

## identity filters
## subordinates by standard tree structure (manager will be found by contract on parent node)
idm.sec.core.filter.IdmIdentity.subordinatesFor.impl=defaultSubordinatesFilter
Use DefaultContractByManagerFilter for overiding in custom module.

DefaultContractByManagerFilter

@since 9.7.0

Finding subordinate contracts of the manager by the IR, tree structures and set guarantees. The subordinate contract is the contract which has its IR on an organizational structure component subordinate to a structure component of the manager's IR. The guarantee can also be configured directly to the IR.

Filter parameters

Configuration:

## identity contract filters
## subordinate contracts by standard tree structure (manager will be found by contract on parent node)
idm.sec.core.filter.IdmIdentityContract.subordinatesFor.impl=default-contract-by-manager-filter

GuaranteeManagersFilter

Finding managers of the entity by the set guarantees. The manager (guarantee) has to be configured directly to the IR.

Filter parameters

Configuration:

## identity filters
idm.sec.core.filter.IdmIdentity.managersFor.impl=guaranteeManagersFilter

GuaranteeContractBySubordinateContractFilter

@since 10.4.0

Finding managers' contracts by the given subordinate contract. The manager (guarantee) has to be configured directly to the IR. All managers' contracts are returned.

Filter parameters

Configuration:

## contract filters
idm.sec.core.filter.IdmIdentityContract.managersByContract.impl=guarantee-contract-by-subordinate-contract-filter

GuaranteeSubordinatesFilter

Finding subordinates by directly configured managers to the IR.

Filter parameters

Configuration:

## identity filters
idm.sec.core.filter.IdmIdentity.subordinatesFor.impl=guaranteeSubordinatesFilter
Use ContractByGuaranteeFilter for overriding in your custom module

ContractByGuaranteeFilter

@since 9.7.0

Finding subordinate contracts by directly configured managers to the IR.

Filter parameters

Configuration:

## identity contract filters
idm.sec.core.filter.IdmIdentityContract.subordinatesFor.impl=contract-by-guarantee-filter

EavCodeManagersFilter

The second option for finding managers in the same way as DefaultManagersFilter with a difference that the superordinate component is not being searched for by tree structure but by the value of an extended (eav) tree component parameter - a code of a different component is stated in the tree component, where there are managers (having IR on the given component) defined.

## identity filters
## managers by relation in eav attribute (manager will be found by code in eav on parent node)
idm.sec.core.filter.IdmIdentity.managersFor.impl=eavCodeManagersFilter
# extended form definition code
idm.sec.core.filter.IdmIdentity.managersFor.formDefinition=default
# extended attribute code - value contains superior node code
idm.sec.core.filter.IdmIdentity.managersFor.formAttribute=parentCode
# extended attribute persistent type, 'shortTextValue' is prefered (indexed column by default), but 'stringValue' is used as default for compatibility reasons
idm.sec.core.filter.IdmIdentity.managersFor.persistentType=shortTextValue

EavCodeManagerContractBySubordinateContractFilter

@since 10.4.0

The second option for finding managers' contracts in the same way as DefaultManagerContractBySubordinateContractFilter with a difference that the manager contract is not being searched for by tree structure but by the value of an extended (eav) tree component parameter - a code of a extended attribute is stated in the tree component, where there are managers (having contract on the given component) defined.

## contract filters
## managers by relation in eav attribute (manager will be found by code in eav on parent node)
idm.sec.core.filter.IdmIdentityContract.managersByContract.impl=eav-code-manager-contract-by-subordinate-contract-filter
# extended form definition code
idm.sec.core.filter.IdmIdentityContract.managersByContract.formDefinition=default
# extended attribute code - value contains superior node code
idm.sec.core.filter.IdmIdentityContract.managersByContract.formAttribute=parentCode
# extended attribute persistent type, 'shortTextValue' is prefered (indexed column by default), but 'stringValue' is used as default for compatibility reasons
idm.sec.core.filter.IdmIdentityContract.managersByContract.persistentType=shortTextValue

<del>EavCodeSubordinatesFilter</del>

Deprecated since 9.7.0. Use new EavCodeContractByManagerFilter filter for override filter behavior.

The second option for finding subordinates in the same way as DefaultManagersFilter with a difference that the superordinate component is not being searched for by tree structure but by the value of an extended (eav) tree component parameter - a code of a different component is stated in the tree component, where there are managers (having IR on the given component) defined. Otherwise the functions and parameters are identical.

## identity filters
## subordinates by relation in eav attribute (subordinates will be found by code in eav on parent node)
idm.sec.core.filter.IdmIdentity.subordinatesFor.impl=eavCodeSubordinatesFilter
# extended form definition code
idm.sec.core.filter.IdmIdentity.subordinatesFor.formDefinition=default
# extended attribute code - value contains superior node code
idm.sec.core.filter.IdmIdentity.subordinatesFor.formAttribute=parentCode
# extended attribute persistent type, 'shortTextValue' is prefered (indexed column by default), but 'stringValue' is used as default for compatibility reasons
idm.sec.core.filter.IdmIdentity.subordinatesFor.persistentType=shortTextValue

EavCodeContractByManagerFilter

The second option for finding subordinate contracts in the same way as DefaultContractByManagerFilter with a difference that the superordinate component is not being searched for by tree structure but by the value of an extended (eav) tree component parameter - a code of a different component is stated in the tree component, where there are managers (having IR on the given component) defined. Otherwise the functions and parameters are identical.

## identity contract filters
## subordinate contracts by relation in eav attribute (subordinate contracts will be found by code in eav on parent node)
idm.sec.core.filter.IdmIdentityContract.subordinatesFor.impl=eav-code-contract-by-manager-filter
# extended form definition code
idm.sec.core.filter.IdmIdentityContract.subordinatesFor.formDefinition=default
# extended attribute code - value contains superior node code
idm.sec.core.filter.IdmIdentityContract.subordinatesFor.formAttribute=parentCode
# extended attribute persistent type, 'shortTextValue' is prefered (indexed column by default), but 'stringValue' is used as default for compatibility reasons
idm.sec.core.filter.IdmIdentityContract.subordinatesFor.persistentType=shortTextValue

Filter agenda

Agenda of registered filter builders is available from menu Setting→ Modules → Filters.

Supported features:

Even filter from disabled module can be set as active ⇒ when module is disabled, then we don't want to filters be broken (respectively no data was returned, when some disabled filter is used, see DisabledFilterBuilder), then check module is disabled is ignored for filter builders.