This chapter describes the query API Stardust provides for building queries and how it is used.
The Stardust Process Engine offers a rich query API for querying
runtime elements. The following concrete Query classes located in the
org.eclipse.stardust.engine.api.query package are available:
They all extend the main Query class, which provides the basic functionality for creating query containers for complex queries. For details on query objects refer to section Query Objects of chapter Objects and Model Elements.
While in most situations it is completely sufficient to obtain runtime objects satisfying certain filter criteria in arbitrary order, in some cases it may be necessary to exactly specify a relative order of retrieved items.
As an example, to address certain quality of service aspects you
may like to retrieve the ActivityInstance of the oldest
activity instance belonging to instances of the process INTERNET_ORDER.
To achieve this you would have to write code like:
ActivityInstanceQuery query = ActivityInstanceQuery.findAlive("INTERNET_ORDER");
query.orderBy(ActivityInstanceQuery.START_TIME);
QueryService qs = ...;
ActivityInstance oldest = qs.findFirstActivityInstance(query);
This sample combines the predefined query for finding activity instances belonging to a certain process with a single additional order criterion.
The methods used to define a sorting order are:
public abstract class Query
{
...
public OrderCriteria orderBy(FilterableAttribute attribute);
public OrderCriteria orderBy(FilterableAttribute attribute, boolean ascending);
public OrderCriteria orderBy(OrderCriterion criterion);
...
}
The first two are used to define an order according to attributes of the objects queried for. The first method implicitly requests ascending order, while the second lets the caller choose between ascending or descending order.
Attributes you can use for ordering are defined in the scope of
the concrete query. For instance, when performing an ActivityInstanceQuery
you may select from the following:
public class ActivityInstanceQuery extends Query
{
public static final Attribute STATE = ...;
public static final Attribute START_TIME = ...;
public static final Attribute LAST_MODIFICATION_TIME = ...;
public static final Attribute ACTIVITY_OID = ...;
public static final Attribute CURRENT_PERFORMER_OID = ...;
public static final Attribute CURRENT_USER_PERFORMER_OID = ...;
public static final Attribute PERFORMED_BY_OID = ...;
public static final Attribute PROCESS_INSTANCE_OID = ...;
public static final Attribute CRITICALITY = ...;
public static final Attribute BENCHMARK_VALUE = ...;
public static final Attribute BENCHMARK_OID = ...;
...
}
Which attributes are supported by the concrete query you want to
perform can be found in the query class's JavaDoc. Attributes are always
static instances of an inner class Attribute.
In case you need a combination of more than one order criterion
you may make use of having the orderBy methods returning an
instance of class OrderCriteria. As the name implies, instances
of OrderCriteria are used to group lists of single order
criteria into one object. The most important methods are:
public final class OrderCriteria implements OrderCriterion
{
...
public OrderCriteria and(FilterableAttribute attribute);
public OrderCriteria and(FilterableAttribute attribute, boolean ascending);
public OrderCriteria and(OrderCriterion criterion);
...
}
You may notice the similarity to the three orderBy
methods shown before. Calling one of the methods appends another order
criterion to the list already set. The list of criteria will later be
evaluated in order of appearance.
To extend the former example we now add another criterion to still find the oldest activity instance, but now additionally requesting to get the instance with the longest idle time in case of multiple instances of the same age.
ActivityInstanceQuery query = ActivityInstanceQuery.findAlive("INTERNET_ORDER");
query.orderBy(ActivityInstanceQuery.START_TIME).and(ActivityInstanceQuery.LAST_MODIFICATION_TIME);
QueryService qs = ...;
ActivityInstance oldest = qs.findFirstActivityInstance(query);
To finish the quick order walk-through, let's come back to the
third orderBy method. Its OrderCriterion parameter may
be used to set a pre-configured complex list of order criteria at once.
For instance, when having a GUI for defining order criteria it may be
useful to evaluate its state once and later reuse the resulting OrderCriteria
object for multiple queries. In terms of our last example this would
mean:
OrderCriteria ordering = new OrderCriteria();
ordering.and(ActivityInstanceQuery.START_TIME).and(ActivityInstanceQuery.LAST_MODIFICATION_TIME);
...
ActivityInstanceQuery query = ActivityInstanceQuery.findAlive("INTERNET_ORDER");
query.orderBy(ordering);
QueryService qs = ...;
ActivityInstance oldest = qs.findFirstActivityInstance(query);
Policies allow to set special options for queries. Using policies you can fine tune the behavior for more complex queries.
The EvaluationPolicy is the interface to be implemented by custom query evaluation policies. The following policies are available:
The ModelVersionPolicy affects query execution in a multi-version model environment. You can use it to restrict query evaluation involving model elements to only consider the currently active model version.
To use this policy, parse a Boolean parameter to determine if the query should be restricted to the active model or not. For example, to initialize a query matching activity instances in all model versions:
public ActivityInstanceQuery()
{
...
setPolicy(new ModelVersionPolicy(false));
...
}
The policies CriticalCostPerExecutionPolicy, CriticalExecutionTimePolicy, CriticalProcessingTimePolicy and PerformanceCriticalityPolicy can be used to determine if process instances are considered critical. They use the following different criteria:
The CriticalCostPerExecutionPolicy determines if process instances are considered critical if their execution costs exceeds a certain limit.
The limits can be defined per priority. The parameters for this policy are the following:
The following example code demonstrates how to use the policy in the Control Center to determine if process instances are critical depending on their cost per execution:
UserWorktimeStatisticsQuery wsQuery = UserWorktimeStatisticsQuery.forAllUsersWithoutWaitTime(); wsQuery.setPolicy(CriticalCostPerExecutionPolicy.criticalityByCost( BusinessControlCenterConstants.getInstanceCostThreshold(BusinessControlCenterConstants.YELLOW_THRESHOLD, 1.0f), BusinessControlCenterConstants.getInstanceCostThreshold(BusinessControlCenterConstants.RED_THRESHOLD,1.0f)));
The CriticalExecutionTimePolicy determines if process instances are critical if their execution time exceeds a certain limit.
The limits can be defined per priority. The policy uses the following three parameters:
The following example code demonstrates the usage of the CriticalExecutionTimePolicy to determine if process instances are critical by using the thresholds of the process instance priorities.
OpenActivitiesStatisticsQuery query = OpenActivitiesStatisticsQuery.forAllProcesses(); query.setPolicy(new CriticalExecutionTimePolicy( Constants.getCriticalDurationThreshold(ProcessInstancePriority.LOW, 1.0f), Constants.getCriticalDurationThreshold(ProcessInstancePriority.NORMAL, 1.0f), Constants.getCriticalDurationThreshold(ProcessInstancePriority.HIGH, 1.0f)));
The CriticalExecutionTimePolicy determines if process instances are considered critical if their processing time exceeds a certain limit.
The limits can be defined per priority. The policy uses the following two parameters:
Similar to the CriticalExecutionTimePolicy, the PerformanceCriticalityPolicy determines if process instances are considered critical if their duration exceeds a certain limit defined per priority.
The limits can be defined per priority. The policy uses the following three parameters:
The DescriptorPolicy specifies if to retrieve descriptors during a query.
The following example query retrieves descriptor values with process instance details:
query.setPolicy(DescriptorPolicy.WITH_DESCRIPTORS);
The following example query does not retrieve descriptor values with process instance details:
query.setPolicy(DescriptorPolicy.NO_DESCRIPTORS);
The following example query retrieves descriptor values with process instance details for a given set of descriptor Ids:
query.setPolicy(DescriptorPolicy.withIds(getVisibleDescriptorsIds()));
Stardust provides a policy
EvaluateByWorkitemsPolicy
to retrieve activity instances based on the workitem table,
which contains only manual/interactive activity instances.
This policy is available for the ActivityInstanceQuery.
If this policy is set, any
ActivityInstanceQuery for getAllActivityInstance or
getActivityInstanceCount is executed on the
workitem
table instead of
the activity_instance
table.
Note that based on this fact, this policy is relevant only for queries on interactive and manual activities that are active (in state application or suspended). Other activities will not be part of the result set.
According to the nature of the ActivityInstanceQuery, the use of
other filters and/or policies should be handled with care as the workitems may
not contain the same details as ActivityInstances.
You can extend a document search from the default repository to either all repositories or to all specified repositories by setting a RepositoryPolicy.
package org.eclipse.stardust.engine.api.query;
import java.util.Collections;
import java.util.List;
public class RepositoryPolicy implements EvaluationPolicy
{
private static final long serialVersionUID = -4922399462085360884L;
private List<String< repositoryIds;
public RepositoryPolicy()
{
repositoryIds = Collections.EMPTY_LIST;
}
public static RepositoryPolicy includeAllRepositories()
{
return new RepositoryPolicy(Collections.EMPTY_LIST);
}
public static RepositoryPolicy includeRepositories(List<String< repositoryIds)
{
return new RepositoryPolicy(repositoryIds);
}
public RepositoryPolicy(List<String< repositoryIds)
{
this.repositoryIds = repositoryIds;
}
public List<String< getRepositoryIds()
{
return repositoryIds;
}
}
Method includeAllRepositories() configures a policy to includes all
available repositories into the search. To create a policy to include a list
of repositories, use includeRepositories(List<String< repositoryIds).
The following example uses a RepositoryPolicy to search for documents in a set of repositories, which is specified as list of repository Ids:
DocumentQuery query = DocumentQuery.findAll(); Documents findDocuments(DocumentQuery query); query.setPolicy(new RepositoryPolicy(<list of repository Ids>));
The following example code shows how to use the StatisticsDateRangePolicy to specify a date range for a user worktime statistics query.
UserWorktimeStatisticsQuery query = UserWorktimeStatisticsQuery.forAllUsers(); List<DateRange< dateRanges = new ArrayList<DateRange<(); dateRanges.add(DateRange.TODAY); dateRanges.add(DateRange.YESTERDAY); dateRanges.add(DateRange.THIS_WEEK); dateRanges.add(DateRange.LAST_WEEK); dateRanges.add(DateRange.THIS_MONTH); dateRanges.add(DateRange.LAST_MONTH); query.setPolicy(new StatisticsDateRangePolicy(dateRanges)); ServiceFactory serviceFactory = getServiceFactory(); userWorktimeStatistics = (UserWorktimeStatistics) serviceFactory.getQueryService().getAllUsers(query);
To control the level of detail for user details, you can use the UserDetailsPolicy:
UserQuery query = UserQuery.findAll(); query.setPolicy(new UserDetailsPolicy(<level>));
whereby <level> can be one of the following:
UserDetailsLevel.Core: The user details only contain first level
attributes of UserBean.UserDetailsLevel.WithProperties: The user details contain the same
attributes as with CORE plus properties.UserDetailsLevel.Full: The user details contain the same attributes
as with WITH_PROPERTIES plus all grants.This policy applies to any query referencing user details in its results. If no
policy is set then UserDetailsLevel.Full will be used.
The method
UserDetailsLevel getDetailsLevel();
in the interface User retrieves the level of details for users.
The method UserService.modifyUser(User changes) will throw the exception
new IllegalOperationException("Operation requires fully initialized user.")
in case the following predicate is not true:
UserDetailsLevel.Full != changes.getDetailsLevel();
To exclude activity instances in activity instance queries, where the user is an excluded user for that activity instance, you can use the ExcludeUserPolicy policy:
ActivityInstanceQuery query = ActivityInstanceQuery.findAll(); query.setPolicy(ExcludeUserPolicy.EXCLUDE_USER);
Refer to class ActivityInstanceQuery for details.
You have the option to determine if the exclude user evaluation is performed
in queries. Set the property
Stardust.Engine.Tuning.Query.ExcludeUser.Evaluation in your server-side
carnot.properties file accordingly. If set to true, ActivityInstanceQueries
evaluate if activities have ExcludeUser actions applied (in case
the ExcludeUserPolicy is applied). If set to false,
which is the default value, no evaluation takes place.
To limit the runtime effort associated with the worklist count retrieval, in case exclude user evaluation is performed, you can configure a threshold up to which the total count is counted exactly. Set the property Stardust.Engine.Tuning.Query.ExcludeUser.MaximumWorklistCount to a maximum count value to be used as threshold. Refer to the Tuning section of chapter Server Side Properties for details on these properties.
Policy HistoricalDataPolicy determines if historical data values are included or excluded in process instance details. The following options are provided:
Please refer to section Querying Process Instance Details including Historical Data of chapter Querying Process Instance Details for an example usage of this policy in a process instance details query.
To determine the inclusion of given event types in process and activity instances, use the HistoricalEventPolicy. The possible event types of type HistoricalEventType are:
The predefined policy ALL_EVENTS includes all event types in the process or activity instance:
public final static HistoricalEventPolicy ALL_EVENTS = new HistoricalEventPolicy( HistoricalEventType.EXCEPTION | HistoricalEventType.STATE_CHANGE | HistoricalEventType.NOTE | HistoricalEventType.DELEGATION);
To create a policy for a given event type respectively event types, use
public HistoricalEventPolicy(int eventTypes)
To add more than one event type, concatenate the types via the logical or operator,
e.g.:
new HistoricalEventPolicy(HistoricalEventType.EXCEPTION | HistoricalEventType.DELEGATION)
To create a policy for given events, use
public HistoricalEventPolicy(HistoricalEventType[] eventTypes)
Activity instance queries having set a HistoricalEventPolicy with
HistoricalEventType.EVENT_EXECUTION will return in ActivityInstance.getHistoricalEvents()
additional HistoricalEvents based on the log entries for that activity instance with:
LogType.Info.equals(logType) AND
LogCode.EVENT.equals(logCode)
HistoricalEvent.getDetails() returns an instance of
org.eclipse.stardust.engine.api.model.EventHandler which describes the
event handler associated to the executed event.
The ProcessCumulationPolicy retrieves the root or scope process for cumulation.
It defines the following predefined policies:
WITH_ROOT_PI - retrieving the process for cumulation including the root processWITH_SCOPE_PI - retrieving the process for cumulation including the scope processWITH_PI - retrieving the process for cumulation including neither root nor scope processWith the ProcessDefinitionDetailsPolicy, you can set the level of detail in which the process definition object is initialized, e.g. if you like to provide general information about a process definition only, not including all details about activities. The following levels are available:
CORE - excludes activities, data paths, triggers and event handlersWITHOUT_ACTIVITIES - excludes activities, but contains data paths, triggers and event handlersFULL - contains all information including activities, data paths, triggers and event handlersNote that the declared and implemented ProcessInterface is always contained. The default level of detail is FULL.
For example, the following code retrieves all process definitions excluding information on activities, data paths, triggers or event handlers:
ServiceFactory sf = ServiceFactoryLocator.get("motu", "motu");
QueryService qs = sf.getQueryService();
ProcessDefinitionDetailsLevel detailsLevel = ProcessDefinitionDetailsLevel.CORE;
ProcessDefinitionQuery query = ProcessDefinitionQuery.findAll();
query.setPolicy(new ProcessDefinitionDetailsPolicy(detailsLevel));
ProcessDefinitions processDefinitions = qs.getProcessDefinitions(query);
With the ProcessInstanceDetailsPolicy, you can set the level of detail in which the process instance object is initialized, e.g. if you like to provide general information about a process instance only, not including all details about activities. The following levels are available:
CORE - the process instance details only contain first level attributes of
ProcessInstanceBeanWITH_PROPERTIES - the process instance details contain same attributes as with CORE
plus all extended attributes.WITH_RESOLVED_PROPERTIES - the process instance details contain same attributes as with
WITH_PROPERTIES plus all extended attributes are resolved, i.e. further detail objects.FULL - process instance details are fully initialized.The default level of detail is WITH_PROPERTIES.
The WorklistLayoutPolicy provides the following policies to specify the result for worklist queries:
The value MERGED_DEPUTY merges deputy relates activity instances into standard layout. This is the default value. One worklist is displayed with several sub participant worklists, as illustrated in the following example:
(top level) UserWorklist containing own workitems and those of private worklists user is being deputy of
(sub) ParticipantWorklist1 (e.g own or inherited grant)
(sub) ParticipantWorklist2 (...)
(sub) ParticipantWorklist3 (...)
Policy value SEPARATE_DEPUTY determines to split the result into one own user worklist with own sub participant worklists. User sub worklists of those users the user is deputy of with their own participant worklists, as shown in the following example:
(top level) UserWorklist containing own workitems
(sub) ParticipantWorklist1 (own or inherited grant)
(sub) ParticipantWorklist2 (...)
(sub) ParticipantWorklist3 (...)
....
(sub) userWorklist1 (for 1st user being deputy of)
(sub) ParticipantWorklist1_1 (inherited grant)
(sub) ParticipantWorklist1_2 (...)
(sub) ParticipantWorklist1_3 (...)
....
(sub) userWorklist2 (for 2nd user being deputy of)
(sub) ParticipantWorklist2_1 (inherited grant)
(sub) ParticipantWorklist2_2 (...)
(sub) ParticipantWorklist2_3 (...)
....
Often it is not needed to get all items resulting from a query but the top n. If combined with a well known order of items you may want to fetch further chunks of data on demand.
You can do so by specifying a SubsetPolicy for your query. Any subset defines a size restriction and optionally a number of items to be skipped. For specifying subsets you set a policy via the query's setPolicy method. To extend the last example to retrieve five instead of one item you have to write code like:
ActivityInstanceQuery query = ActivityInstanceQuery.findAlive("INTERNET_ORDER");
Date date = ...;
query.where(ActivityInstanceQuery.START_TIME.greaterOrEqual(date.getTime()));
FilterOrTerm itemFilter = query.getFilter().addOrTerm();
itemFilter.or(DataFilter.isEqual("ORDERED_ITEM_ID", "CARNOT_MUG")).or(DataFilter.isEqual("ORDERED_ITEM_ID", "CARNOT_SHIRT"));
query.orderBy(ActivityInstanceQuery.START_TIME).and(ActivityInstanceQuery.LAST_MODIFICATION_TIME);
query.setPolicy(new SubsetPolicy(5));
QueryService qs = ...;
ActivityInstances oldest = qs.getAllActivityInstances(query);
This will get you up to five items matching the given filter criteria. If you later decide to fetch the next chunk you may simply write code like:
ActivityInstanceQuery query = oldest.getQuery(); SubsetPolicy subset = (SubsetPolicy) query.getPolicy(SubsetPolicy.class); query.setPolicy(SubsetPolicy.nextChunk(subset)); ActivityInstances nextChunk = qs.getAllActivityInstances(query);
Especially as any query result object carries its query the last code snippet allows to generically page through result sets, for instance triggered by GUI operations.
Stardust provides various factory methods to execute queries on objects at runtime. Sometimes these well-defined query semantics do not meet specific requirements and return a huge amount of data, or do not retrieve the accurate data. Custom Filters help you to get the appropriate data by fetching only selected portion of the query results. You can also use Custom Filters to extend the existing query capabilities.
A Custom Filter is a part of the query. It dynamically intercepts
all requests and responses, and transforms or uses the information
contained in the requests or responses. It does not create responses by
itself. You can also specify one or more filter criteria if required.
All filters are implementations of the interface FilterCriterion.
Currently, Stardust provides three types of Custom Filters - attribute
filters, structural filters and filter terms.
Attribute filter is the simplest one. You can use it to filter the attribute values of the objects. You can use a subset of Java's operators in the filter expression. For instance, you can test for equality, inequality, pattern matches, range matches, or NULL. For criteria, you can use any attribute that is valid for defining order criteria.
Attributes are defined as static constants of an inner class
Attribute in scope of the actual query class. Attribute itself is a
specialization of FilterableAttribute, which in turn defines
several factory methods for creating filter criteria against the actual
attribute. You can refer to the JavaDoc of class FilterableAttribute
for a complete list.
An easiest way to use the Custom Filters is to use it with a predefined query. We can use a Custom Filter in the previous example to find activity instances started after a certain date.
ActivityInstanceQuery query = ActivityInstanceQuery.findAlive("INTERNET_ORDER");
Date date = ...;
query.getFilter().and(ActivityInstanceQuery.START_TIME.greaterOrEqual(date.getTime()));
query.orderBy(ActivityInstanceQuery.START_TIME).and(ActivityInstanceQuery.LAST_MODIFICATION_TIME);
QueryService qs = ...;
ActivityInstance oldest = qs.findFirstActivityInstance(query);
Note that query.getFilter().and(filter) is functionally equivalent to query.where(filter).
This is a more advanced way of filtering the data. In this
method, the data may not be directly attributed to the query object. For
instance, items related to workflow data of a specific value, or items
related to specific process definitions. You can specify the actual
relation between these items in the query. Note that the details of a
process instance directly relate to workflow data and process
definitions. The details of activity instances relate indirectly via the
process instance they belong to, but additionally relate to an activity
definition. Refer to the query specific javadoc for actual set
of filters available.
As an example, we can modify the previous query to additionally filter for activity instances belonging to process instances containing a certain workflow data identifying the ordered item:
ActivityInstanceQuery query = ActivityInstanceQuery.findAlive("INTERNET_ORDER");
Date date = ...;
query.where(ActivityInstanceQuery.START_TIME.greaterOrEqual(date.getTime()));
query.where(DataFilter.isEqual("ORDERED_ITEM_ID", "CARNOT_MUG"));
query.orderBy(ActivityInstanceQuery.START_TIME).and(ActivityInstanceQuery.LAST_MODIFICATION_TIME);
QueryService qs = ...;
ActivityInstance oldest = qs.findFirstActivityInstance(query);
Applying structural filters is as easy as applying attribute filters. It's the job of the process engine to perform all joins and traversals needed for the query.
Note that some of the structural filters require an additional
post-processing step. This adds a little overhead to the query
execution. Please consult the JavaDoc to get additional
information.
In this method, you can combine several simple filter criteria to
build a complex and efficient filter. You can do this in two ways: You
can either use FilterAndTerm, or use FilterOrTerm.
Both of them are specializations of FilterTerm, which has some
interesting methods as follows:
public abstract class FilterTerm
{
...
public FilterTerm add(FilterCriterion filter);
public FilterAndTerm addAndTerm();
public FilterOrTerm addOrTerm();
...
}
You can add arbitrary filter criteria by calling the add()
method, which returns a FilterTerm class. This method calls
itself recursively, thus allowing for chained calling like add(filter1).add(filter2).
You can use the other two methods to create sub-terms and build deeply
nested filter trees. FilterAndTerm and FilterOrTerm
are provided for convenience, to improve type safety while building
filter terms.
Note that every query implicitly contains a top-level AND
term. Any filter criterion you add with the where() method is
added to the top-level AND term. Adding sub-terms resembles the
practice of using braces when building complex logical terms. You may
have noticed that adding another AND term to the query's
top-level AND term doesn't produce an efficient query. You can
add an OR sub-term for making it more flexible and effective. We
can extend the previous example by not looking for order processes for
one, but one out of two possible items:
ActivityInstanceQuery query = ActivityInstanceQuery.findAlive("INTERNET_ORDER");
Date date = ...;
query.where(ActivityInstanceQuery.START_TIME.greaterOrEqual(date.getTime()));
FilterOrTerm itemFilter = query.getFilter().addOrTerm();
itemFilter.or(DataFilter.isEqual("ORDERED_ITEM_ID", "CARNOT_MUG")).or(DataFilter.isEqual("ORDERED_ITEM_ID", "CARNOT_SHIRT"));
query.orderBy(ActivityInstanceQuery.START_TIME).and(ActivityInstanceQuery.LAST_MODIFICATION_TIME);
QueryService qs = ...;
ActivityInstance oldest = qs.findFirstActivityInstance(query);
Data filters are not restricted to simple equality tests. They also provide rich operators for filtering the attributes. The following example is an improved way of writing the previous one, which also has improved performance.
ActivityInstanceQuery query = ActivityInstanceQuery.findAlive("INTERNET_ORDER");
Date date = ...;
query.where(ActivityInstanceQuery.START_TIME.greaterOrEqual(date.getTime())).and(DataFilter.in("ORDERED_ITEM_ID", Arrays.asList(
new String[] {"CARNOT_MUG", "CARNOT_SHIRT"})));
query.orderBy(ActivityInstanceQuery.START_TIME).and(ActivityInstanceQuery.LAST_MODIFICATION_TIME);
QueryService qs = ...;
ActivityInstance oldest = qs.findFirstActivityInstance(query);
You can use arbitrary complex sub-terms to build complex filter criteria for runtime queries.
Structured data can be used in queries to retrieve process and activity instances. To specify query conditions against structured data, XPath expressions can be specified as a third parameter to queries.
The query
query.where(DataFilter.isEqual("struct_1", "order/qty", new Integer("77"))).and(DataFilter.isEqual("struct_1", "order/ordernr", "N2"));
searches for orders, that have both qty=77 and ordernr=N2.
If in some instance of structured data orderbook has two orders
qty=77,ordernr=N1 andqty=22,ordernr=N2this structured data will not match the search criteria. The query
query.where(DataFilter.isEqual("struct_1", "order/qty", new Integer("77"))).and(DataFilter.isEqual("struct_1", "order/customer/address/street", "North")));
The query
query.where(DataFilter.isEqual("struct_1", "order/customer/address/street", "North"));
filters for one specific attribute. The query
query.where(DataFilter.isEqual("struct_1", "order/qty", new Integer("77"))).and(DataFilter.isEqual("struct_1", "order/ordernr", "N2"));
filters for two attributes - the same entity is assumed. The query
query.where(DataFilter.isEqual("struct_1", "order/qty", new Integer("77"))).and(DataFilter.isEqual("struct_1", "order/customer/address/street", "North")).and(DataFilter.isEqual("struct_1", "order/customer/name", "James"))
.and(DataFilter.isEqual("struct_1", "status", "OPEN"));
filters for four different attributes in the hierarchy.
The query
query.getFilter().addOrTerm().add(DataFilter.isEqual("struct_1", "order/qty", new Integer("2"))).add(DataFilter.isEqual("struct_1", "order/qty", new Integer("100")));
applies an OR filter in one entity, whereby
query.getFilter().addOrTerm().add(DataFilter.isEqual("struct_1", "order/qty", new Integer("77"))).add(DataFilter.isEqual("struct_1", "order/ordernr", "N1"));
applies and OR filter in different entities.
The query
query.where(DataFilter.isEqual("struct_1", "order/customer/address/street", "North")).and(DataFilter.isEqual("struct_2", "qty", new Integer("1001")));
filters for two data in the process.