Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright (C) 2019 Bonitasoft S.A.
* Bonitasoft, 32 rue Gustave Eiffel - 38000 Grenoble
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation
* version 2.1 of the License.
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301, USA.
**/
package org.bonitasoft.engine.persistence;
import static java.util.Collections.emptySet;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.Session;
import org.hibernate.query.Query;
/**
* @author Baptiste Mesta
*/
@Slf4j
abstract class QueryBuilder {
private final Query baseQuery;
private final boolean wordSearchEnabled;
private final OrderByCheckingMode orderByCheckingMode;
private final AbstractSelectDescriptor selectDescriptor;
private final QueryGeneratorForFilters queryGeneratorForFilters;
private final QueryGeneratorForSearchTerm queryGeneratorForSearchTerm;
private final QueryGeneratorForOrderBy queryGeneratorForOrderBy;
StringBuilder stringQueryBuilder;
private Map classAliasMappings;
private Session session;
private long tenantId;
private boolean cacheEnabled;
private Map parameters = new HashMap<>();
QueryBuilder(Session session, Query baseQuery, OrderByBuilder orderByBuilder,
Map classAliasMappings,
char likeEscapeCharacter, boolean wordSearchEnabled, OrderByCheckingMode orderByCheckingMode,
AbstractSelectDescriptor selectDescriptor) {
this.session = session;
this.classAliasMappings = classAliasMappings;
stringQueryBuilder = new StringBuilder(baseQuery.getQueryString());
this.baseQuery = baseQuery;
this.wordSearchEnabled = wordSearchEnabled;
this.orderByCheckingMode = orderByCheckingMode;
this.selectDescriptor = selectDescriptor;
this.queryGeneratorForFilters = new QueryGeneratorForFilters(classAliasMappings,
likeEscapeCharacter);
this.queryGeneratorForSearchTerm = new QueryGeneratorForSearchTerm(likeEscapeCharacter);
this.queryGeneratorForOrderBy = new QueryGeneratorForOrderBy(classAliasMappings, orderByBuilder);
}
public String getQuery() {
return stringQueryBuilder.toString();
}
void appendFilters(List filters, SearchFields multipleFilter, boolean enableWordSearch) {
Set specificFilters = emptySet();
if (!filters.isEmpty()) {
if (!hasWHEREInRootQuery(stringQueryBuilder.toString())) {
stringQueryBuilder.append(" WHERE (");
} else {
stringQueryBuilder.append(" AND (");
}
QueryGeneratorForFilters.QueryGeneratedFilters whereClause = queryGeneratorForFilters.generate(filters);
specificFilters = whereClause.getSpecificFilters();
stringQueryBuilder.append(whereClause.getFilters());
stringQueryBuilder.append(")");
parameters.putAll(whereClause.getParameters());
}
if (multipleFilter != null && multipleFilter.getTerms() != null && !multipleFilter.getTerms().isEmpty()) {
handleMultipleFilters(stringQueryBuilder, multipleFilter, specificFilters, enableWordSearch);
}
}
static boolean hasWHEREInRootQuery(String query) {
// We simply remove all blocks that are in parenthesis in order to remove all subqueries
// Then we check if there is the `where` word here
return removeAllParenthesisBlocks(query.toLowerCase()).contains("where");
}
private static String removeAllParenthesisBlocks(String q) {
StringBuilder stringBuilder = new StringBuilder(q.length());
int depthCounter = 0;
for (char c : q.toCharArray()) {
switch (c) {
case '(':
depthCounter++;
break;
case ')':
depthCounter--;
break;
default:
if (depthCounter == 0) {
stringBuilder.append(c);
}
}
}
return stringBuilder.toString();
}
private void handleMultipleFilters(final StringBuilder builder, final SearchFields multipleFilter,
final Set specificFilters,
final boolean enableWordSearch) {
final Map, Set> allTextFields = multipleFilter.getFields();
final Set fields = new HashSet<>();
for (final Map.Entry, Set> entry : allTextFields.entrySet()) {
final String alias = classAliasMappings.get(entry.getKey().getName());
for (final String field : entry.getValue()) {
fields.add(alias + '.' + field);
}
}
fields.removeAll(specificFilters);
if (!fields.isEmpty()) {
final List terms = multipleFilter.getTerms();
applyFiltersOnQuery(builder, fields, terms, enableWordSearch);
}
}
private void applyFiltersOnQuery(final StringBuilder queryBuilder, final Set fields,
final List terms, final boolean enableWordSearch) {
if (!hasWHEREInRootQuery(queryBuilder.toString())) {
queryBuilder.append(" WHERE ");
} else {
queryBuilder.append(" AND ");
}
queryBuilder.append("(");
QueryGeneratorForSearchTerm.QueryGeneratedSearchTerms result = queryGeneratorForSearchTerm.generate(fields,
terms, enableWordSearch);
queryBuilder.append(result.getSearch());
queryBuilder.append(")");
parameters.putAll(result.getParameters());
}
void appendOrderByClause(List orderByOptions, Class extends PersistentObject> entityType)
throws SBonitaReadException {
String result = queryGeneratorForOrderBy.generate(orderByOptions, entityType);
stringQueryBuilder.append(result);
}
boolean hasChanged() {
return !baseQuery.getQueryString().equals(stringQueryBuilder.toString());
}
public abstract void setTenantId(Query query, long tenantId);
abstract Query rebuildQuery(AbstractSelectDescriptor selectDescriptor, Session session, Query query);
void manageFiltersAndParameters(AbstractSelectDescriptor selectDescriptor, boolean enableWordSearch)
throws SBonitaReadException {
if (selectDescriptor.hasAFilter()) {
final QueryOptions queryOptions = selectDescriptor.getQueryOptions();
appendFilters(queryOptions.getFilters(), queryOptions.getMultipleFilter(),
enableWordSearch);
}
if (selectDescriptor.hasOrderByParameters()) {
appendOrderByClause(selectDescriptor.getQueryOptions().getOrderByOptions(),
selectDescriptor.getEntityType());
}
}
public QueryBuilder tenantId(long tenantId) {
this.tenantId = tenantId;
return this;
}
public QueryBuilder cache(boolean cacheEnabled) {
this.cacheEnabled = cacheEnabled;
return this;
}
private void setParameters(final Query query, final Map inputParameters) {
for (final Map.Entry entry : inputParameters.entrySet()) {
final Object value = entry.getValue();
if (value instanceof Collection>) {
query.setParameterList(entry.getKey(), (Collection>) value);
} else {
query.setParameter(entry.getKey(), value);
}
}
}
public Query build() throws SBonitaReadException {
manageFiltersAndParameters(selectDescriptor, wordSearchEnabled);
Query query = baseQuery;
if (hasChanged()) {
query = rebuildQuery(selectDescriptor, session, baseQuery);
}
addConstantsAsParameters(query);
setTenantId(query, tenantId);
setParameters(query, selectDescriptor.getInputParameters());
query.setFirstResult(selectDescriptor.getStartIndex());
query.setMaxResults(selectDescriptor.getPageSize());
query.setCacheable(cacheEnabled);
checkOrderByClause(query);
return query;
}
protected abstract void addConstantsAsParameters(Query query);
private void checkOrderByClause(final Query query) {
if (!query.getQueryString().toLowerCase().contains("order by")) {
switch (orderByCheckingMode) {
case NONE:
break;
case WARNING:
log.warn(
"Query '{}' does not contain 'ORDER BY' clause. It's better to modify your query to order" +
" the result, especially if you use the pagination.",
query.getQueryString());
break;
case STRICT:
default:
throw new IllegalArgumentException("Query " + query.getQueryString()
+ " does not contain 'ORDER BY' clause hence is not allowed. Please specify ordering before re-sending the query");
}
}
}
/*
* escape for other things than like
*/
static String escapeString(final String term) {
// 1) escape ' character by adding another ' character
return term
.replaceAll("'", "''");
}
/*
* escape for like
*/
static String escapeTerm(final String term, String likeEscapeCharacter) {
// 1) protect escape character if this character is used in data
// 2) escape % character (sql query wildcard) by adding escape character
// 3) escape _ character (sql query wildcard) by adding escape character
return term
.replace(likeEscapeCharacter, likeEscapeCharacter + likeEscapeCharacter)
.replace("%", likeEscapeCharacter + "%")
.replace("_", likeEscapeCharacter + "_");
}
Map getQueryParameters() {
return parameters;
}
}