The service layer provides services to various consumers in the web layer as well as web service consumers. There are several types of services that serve different roles in the application.
Persistence Services provide the capability to save and retrieve domain objects. Persistence Services extend from
AbstractEpPersistenceServiceImpl and offer methods for adding new domain objects, retrieving domain objects by their identifier, and searching for domain objects with specific criteria.
PersistenceServices are named
X is the class name of the objects that it can save and retrieve.
Domain services typically implement the logic for a use case that is inappropriate for encapsulation by any one domain object. For example, a service that performs a checkout will contain logic for the flow of the interaction between several domain objects. This domain service logic is typically at a higher level of abstraction than the fine-grained domain logic that is implemented by an individual domain object.
Domain services will often use other services in combination with domain object logic to accomplish a task. For example, the checkout service uses domain logic to check for sufficient inventory while using the InventoryService persistence service to persist inventory levels.
In Elastic Path, domain service logic specific to a particular domain object is often implemented within the Persistence Service for that object.
Integration services implement functionality that is invoked by domain services but considered outside the domain of an ecommerce application and typically integrate with other systems or technologies. The following are examples of integration services.
EmailService- Sends email on behalf of other services
CustomerIndexBuildService- Constructs a search index used by the Lucene search feature
BirtReportService- Provides access to the BIRT (Business Intelligence Reporting Tool) reporting engine
System services handle various concerns that cut across many parts of the application. These services are typically provided by Spring and configured in Spring configuration files. Examples of System services include object lifecyle management, caching, transactions, security, and scheduling.
Web services expose service layer functionality to web services clients. These services are ultimately delivered to external systems via SOAP (Simple Object Access Protocol).
Catalog search allows a customer using the front end or a sales representative using the Commerce Manager to find products by keywords. At configured intervals, keywords are extracted from each product in the catalog and stored in a Solr index for fast searching.
Key classes and files
SearchRequestImpl- A search request representation
SearchResultImpl- A search result representation
SearchServiceImpl- A service for searching the product catalog
ProductCategorySearchCriteria- A product search criteria representation
ProductQueryComposerImpl- A Solr query composer for products
SolrIndexSearchServiceImpl- A service for dispatching search requests to the
SolrIndexSearchResultImpl- A Solr result representation
SolrIndexSearcherImpl- A searcher that can read Lucene-based indexes
How it works
A user inputs a string of keywords, and possibly a category restriction, into the search fields and clicks search.
This invokes the
SearchServicewith the following input:
- The user’s
ShoppingCart, which is used to apply promotion rules
ProductLoadTuner, which determines how much of a product’s data is loaded
COMMERCE/STORE/SEARCH/searchCategoriesFirstsystem setting whether it should search for categories before products.
SearchServicefinds a category, the search stops and returns the category page.
If no categories are found,
ProductCategorySearchCriteriato the injected
SolrIndexSearchService, which returns an empty
SolrIndexSearchResultthat has been injected with a
SearchServiceapplies pagination to the
SolrIndexSearchResultand delegates to the
ProductQueryComposerto generate a Solr query and runs a search.
If no results are found,
ProductQueryComposerto generate a Fuzzy query and runs a Fuzzy search.
SearchServiceregains control with the populated
If not enough results are returned,
SearchServiceattempts to generate suggestions, as described by Search Suggestions.
SearchServicereturns the results to the
SearchControlleralong with any suggestions.
By default, the data included in each object in the result set is determined by the
productLoadTunerForBrowsingAndSearch. For more information, see Load tuners.
Lucene includes functionality for performing fuzzy searches. A fuzzy search searches for terms that are similar but not exactly equal to the terms specified by the user. Elastic Path uses fuzzy search functionality to look for possible results when exact matches are not found.
Fuzzy search uses the Search Settings system setting.
The minimum similarity value is a value between zero and one that sets the required similarity between the query term and the matching terms. For example, if
COMMERCE/SEARCH/minimumSimilarity is set to
- A term of the same length as the query term is considered similar to the query term if the edit distance between both terms is less than
The edit distance is a measure of similarity between two strings and distance is measured as the number of character deletions, insertions, or substitutions required to transform one string to the other string.
Another example, the edit distance between "kitten" and "sitting" is 3, since these three edits change one into the other, and there is no way to do it with fewer than three edits:
- Kitten ? Sitten (substitution of ‛k’ for ‛s’)
- Sitten ? Sittin (substitution of ‛e’ for ‛i’)
- Sittin ? Sitting (insert ‛g’ at the end)
Key classes and files
A data access object for Lucene searching. This class contains logic for executing fuzzy searches when no exact matches are found.
Implements a method,
composeFuzzyQuery(..), that creates a new
FuzzyQueryLucene object. The object is populated with the search terms and configuration options specified in the search settings
Search suggestions enable the user to select from one or more alternate search phrases if their original search phrase returned no results. The alternate search phrases attempt to correct any potential typos or misspellings that the original search phrase contains.
Key classes and files
Parses a supplied query, and checks the spelling index to see if there are any suggestions for terms in that query.
A service for dispatching search requests to the SolrIndexSearcher.
Creates a spelling index using the product index’s content field.
A service for searching the product catalog
To configure Fuzzy Search and Search Suggestions, see the Search Settings page.
QueryService interface simplifies the process for creating new domain object queries.
QueryService utilizes the Query Object Pattern, to enable users to generate customized queries without having to understand the details of the domain object database tables.
QueryService automatically generates the Java Persistence Query Language (JPQL) required to access domain objects.
QueryService builds the JPQL query from QueryCriteria objects that are mapped to domain object properties, so all a user needs to know are the properties of the domain object they are querying.
A call to
QueryService has the following syntax:
QueryResult<R> queryResult = queryServiceImpl<T>.query(QueryCriteria<T> criteria);
Three main components to the QueryService:
QueryResult interface provides the methods for getting results from the query.
The generic type
<R> depends on the type of result returned by the query. The
QueryService interface requires you to specify the result’s type. For more information on specifying the type, see Building a Query with QueryService.
Each domain object has its own QueryService implementation. Out of the box, Elastic Path has the following
QueryCriteria specifies the statements the query will perform. Refer to Building a Query with
QueryService for more details.
Building Query with
QueryService saves you from having to create statements to query the database. By creating
QueryCriteria objects, you can query the database without needing to know the database schema. The
QueryCriteria object is built by a
CriteriaBuilder and is automatically converted into JPQL and executed by the
Below is a query example that returns products with a particular category UID:
QueryResult<Product> queryResult = queryService.query( CriteriaBuilder.criteriaFor(Product.class) .with(CategoryRelation.having().uids(categoryUid)) .usingLoadTuner(loadTuner) .returning(ResultType.ENTITY) );
QueryCriteria objects have five different components, as shown in the sample above:
Specify the Domain Class
To create a QueryCriteria object, you need to call the
QueryCriteria first component specifies the domain class. This domain class must match the generic type of the
QueryService implementation to properly generate the JPQL query.
ProductQueryService, which implements the
QueryService<Product> interface, needs Product
QueryCriteria to create Product queries.
Define the Query Relations
To filter query results against particular properties, you can define
QueryCriteria second component is optional and specifies the properties and values searched by the query. The
with() method takes in a Relation object, which identifies a property and value. Relations are explained in further detail in
QueryService Relations. You can chain multiple
with() statements together to refine your queries.
In the example
with() statement, the
CategoryRelation object is used to query for Products with a specific category UID.
Define the Date Range
To filter query results within a specific time frame, you can use either the
inDateRange() method or
QueryCriteria third component is optional and restricts the results returned by date. The
modifiedAfter() method takes in a single Date and returns results that were modified after the given date. The
inDateRange() method takes in a start Date and an end Date and returns results that were modified within the given time frame.
Specify a Load Tuner
To control the amount of associated object data that is retrieved from the database, you can specify a load tuner with
QueryCriteria fourth component is optional. By using a load tuner, you avoid retrieving large object graphs when you only need a subset of the data. For example, a product has a brand, category, images, and skus. If you are querying products for brand, then you can use a load tuner to avoid retrieving product images.
To use a load tuner in QueryService, you must define the load tuner bean in the Elastic Path core. You can define domain level load tuners in
ep-core/src/main/resources/spring/service/service.xml and persistence level load tuners in
Query Return Type
To specify the type of results the query returns, you need to call the
QueryCriteria fifth component specifies the query
ResultType. Out-of-the-box, Elastic Path supports the following result types:
|The domain class. (eg. Product)||Returns the entity objects. For example, a Product query with |
|Returns the objects’ uidPk.|
|Returns the objects’ GUID.|
|Returns a |
|Returns a |
When building a query, you must specify the generic type of the
QueryResult as results are returned in a List. This generic type depends on the
ResultType returned by the query. Queries return an empty list if no results are found.
Relation defines a domain object’s query relationships. Relations encapsulate the knowledge QueryService requires for creating JPQL queries, such as column names, aliases, and how joins are handled.
When building the
QueryCriteria, you can use Relations to identify the properties and values filtered by the query. For example, you use a Relation to query for Products with a specific Product UID:
CriteriaBuilder.criteriaFor(Product.class) .with(ProductRelation.having().uids(productUid)) .returning(ResultType.ENTITY)
Relations are inserted into the
QueryCriteria with the
with() method. You can insert multiple Relations into the
QueryCriteria by chaining with() methods. For example, the following query looks for Products with with a specific Brand UID and Category UID:
CriteriaBuilder.criteriaFor(Product.class) .with(CategoryRelation.having().uids(categoryUid)) .with(BrandRelation.having().uids(brandUid)) .returning(ResultType.ENTITY)
QueryService requires a valid Relation between the object you are querying and the object encapsulated by the Relation. A Relation is valid if the object encapsulated by the Relation is a property of the object being queried.
For example, a
BrandRelation is valid when you query a Product since Product has a Brand property. However, a
ContentSpaceRelation is invalid since Product and
ContentSpace are unrelated.
Building a Relation
Creating the Relation object
To create a relation object, you need to call the Relation class’ static
To specify the object properties a query looks up, you call a Relation’s identifier methods. Each identifier method maps to a property of the Relation’s domain object and provides information on how to query the property.
Out of the box, Elastic Path Relation classes support four identifier methods for querying object properties:
For example, to query for a Store with a specific name, use the
names() identifier method: