Filters
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:
- by service - predicates are constructed in
AbstractReadDtoService#toPredicates
method. This predicates are statically implemented and not overidable. - By registered filter builders - A mechanism for dynamic registry and composing of filters has been developed in the application for searching the data in IdM (identities, roles, tree structure components, etc.). A new filter can be registered for existing REST services in any module. Filter builder can be registered by custom module and can override filter builder from other module (e.g. filter in custom module can override core filter behavior).
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).
Filter can be used by authoritazation policy evaluator for securing data access.
Filter builder
The filter (FilterBuilder
) is registered with the given key (FilterKey
):
entityClass
- a domain type for which it is intendedname
- the name of the item during which the filter is actively evaluated if it is stated in the filtering criteria (⇒get
parameter)
Evaluating of filters is done by FilterManager
, which searches over the domain type during construction:
- collects all registered active filters by a key:
- complying with the given domain type
- complying with the name of the item existing in the parameters by which it is being filtered
- and calls method
getPredicate
over all the found filters the results of which (if there are some) are merged into unified searching criteria via operatorand
.
A filter must implement these methods:
getName
- returns the item name - see abovegetPredicate
- construction of the searching criteria themselvesfind
- returns data (objects by the domain type - see above) solely by the predicate constructed above
The following ready-made abstract classes can be used for constructing a new filter:
BaseFilterBuilder
- provides the base implementation for working with the configuration (see below)AbstractFilterBuilder
- provides the base implementation offind
method based on the repository handed in the constructor
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:
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.
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.
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
managersFor
- a key parameter; uuid of the subordinate for which the searched are managersmanagersByTreeType
- an additional parameter; if it is entered, the managers are being searched for only by the IR with the given structure typemanagersByContract
- an additional parameter; if it is entered, the managers are being searched for only by the given IRincludeGuarantees
- True ⇒ it is being searched for managers by tree structures and managers (guarantee) configured directly to the IR. False ⇒ only managers by tree structures.validContractManagers
- an additional parameter; valid now or in future contracts. True ⇒ managers of contracts ended in the past will not be returned. False ⇒ managers of contracts ended in the past will be returned. All managers otherwise.
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
managersByContract
- a key parameter; uuid of the subordinate contract for which the searched are managers' contractsincludeGuarantees
- True ⇒ it is being searched for managers' contracts by tree structures and by direct guarantees. False ⇒ only managers' contracts by tree structures.validContractManagers
- an additional parameter; valid now or in future contracts. True ⇒ manager contracts of subordinate contract ended in the past will not be returned. False ⇒ manager contracts of subordinate contract ended in the past will be returned. All managers' contracts otherwise.
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
subordinatesFor
- a key parameter; uuid of the manager for which the searched are subordinatessubordinatesByTreeType
- an additional parameter; if it is entered, the subordinates are being searched for only by the IR with the given structure typeincludeGuarantees
- True ⇒ it is being searched for subordinates by tree structures and subordinates by managers (guarantee) configured directly to the IR. False ⇒ only subordinates by tree structures.
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
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
subordinatesFor
- a key parameter; uuid of the manager for which the searched are subordinate contractssubordinatesByTreeType
- an additional parameter; if it is entered, the subordinate contracts are being searched for only by the IR with the given structure typeincludeGuarantees
- True ⇒ it is being searched for subordinate contracts by tree structures and subordinate contracts by managers (guarantee) configured directly to the IR. False ⇒ only subordinate contracts by tree structures.
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
managersFor
- a key parameter; uuid of the subordinate for which the searched are managersmanagersByTreeType
- if it is entered, the filter is disabled (⇒ returns no data ~disjunction
)includeGuarantees
- has to be true ⇒ it is being searched for managers configured directly to the IR. False ⇒ returns no data ~disjunction
.validContractManagers
- an additional parameter; valid now or in future contracts. True ⇒ managers of contracts ended in the past will not be returned. False ⇒ managers of contracts ended in the past will be returned. All managers otherwise. 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
managersByContract
- a key parameter; uuid of the subordinate contract for which the searched are managers' contractsvalidContractManagers
- an additional parameter; valid now or in future contracts. True ⇒ managers of contracts ended in the past will not be returned. False ⇒ managers of contracts ended in the past will be returned. All managers otherwise. 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
subordinatesFor
- a key parameter; uuid of the manager for which the searched are subordinatessubordinatesByTreeType
- if it is entered, the filter is disabled (⇒ returns no data ~disjunction
)includeGuarantees
- has to be true ⇒ it is being searched for subordinates by directly configured managers to the IR. False ⇒ returns no data ~disjunction
.
Configuration:
## identity filters idm.sec.core.filter.IdmIdentity.subordinatesFor.impl=guaranteeSubordinatesFilter
ContractByGuaranteeFilter
for overriding in your custom module
ContractByGuaranteeFilter
@since 9.7.0
Finding subordinate contracts by directly configured managers to the IR.
Filter parameters
subordinatesFor
- a key parameter; uuid of the manager for which the searched are subordinate contractssubordinatesByTreeType
- if it is entered, the filter is disabled (⇒ returns no data ~disjunction
)includeGuarantees
- has to be true ⇒ it is being searched for subordinate contracts by directly configured managers to the IR. False ⇒ returns no data ~disjunction
.
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>
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:
- All reqistered dynamic filters are shown.
- All filters implemented internally in service (description
Internal service implementation (toPredicates).
is hard coded for this filters). - Currently not active filters can be activated (button is available).
- Filters are grouped by entity, which can be filtered by.
DisabledFilterBuilder
), then check module is disabled is ignored for filter builders.