Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ protected void executeCommand() {
tagsDirector.removeTag(getTag().getTagId());
String[] IDsArray = tagIdAndChildrenIds.split("[,]", -1);
for (String id : IDsArray) {
id = id.replace("'", "");
id = id.replace("\"", "");
tagDao.remove(new Guid(id));
}
setSucceeded(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ private QueryData initQueryData(boolean useCache) {
// statically, therefore , in order to reflect changes in the parent tree
// we should not rely on the cached query in such case and have to build the
// query from scratch.
if (!containsStaticInValues(data.getQuery())) {
if (!containsStaticValues(data.getQuery())) {
queriesCache.put(searchKey, data);
}
}
Expand Down Expand Up @@ -671,8 +671,8 @@ protected String getDefaultAuthz() {
return AuthenticationProfileRepository.getInstance().getProfiles().get(0).getName();
}

private static boolean containsStaticInValues(String query) {
final String MATCH_IN_TAG_ID_CLAUSE = "with_tags.tag_id in";
return query.toLowerCase().contains(MATCH_IN_TAG_ID_CLAUSE);
private static boolean containsStaticValues(String query) {
final String MATCH_TAG_NAMES_CONDITION = "with_tags.tag_names &&";
return query.toLowerCase().contains(MATCH_TAG_NAMES_CONDITION);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
Expand Down Expand Up @@ -248,11 +249,21 @@ public String getTagNamesAndChildrenNamesByRegExp(String tagNameRegExp) {
return sb.toString();
}

@Override
public String getTagsNamesByRegExp(String tagNameRegExp) {
tagNameRegExp = tagNameRegExp.replace("*", ".*");
final Pattern tagNamePattern = Pattern.compile(String.format("^%1$s$", tagNameRegExp));

return tagsMapByName.keySet().stream()
.filter(name -> tagNamePattern.matcher(name).matches())
.collect(Collectors.joining(", "));
}

private static void recursiveGetTagsAndChildrenByRegExp(String tagNameRegExp, StringBuilder sb, Tags tag, TagReturnValueIndicator indicator) {
if (tag.getChildren() != null && !tag.getChildren().isEmpty()) {
tagNameRegExp = BACKSLASH_REMOVER.matcher(tagNameRegExp).replaceAll("");
Pattern tagNamePattern = Pattern.compile(tagNameRegExp);
for (Tags child : tag.getChildren()) {
Pattern tagNamePattern = Pattern.compile(tagNameRegExp);
if (tagNamePattern.matcher(child.getTagName()).find()) {
// the tag matches the regular expression -> add it and all its
// children
Expand Down Expand Up @@ -280,7 +291,7 @@ private static void recursiveGetTagsAndChildrenByRegExp(String tagNameRegExp, St

private static StringBuilder getTagIdAndChildrenIds(Tags tag) {
StringBuilder builder = new StringBuilder();
builder.append("'").append(tag.getTagId()).append("'");
builder.append('"').append(tag.getTagId()).append('"');

for (Tags child : tag.getChildren()) {
builder.append(",").append(getTagIdAndChildrenIds(child));
Expand All @@ -290,10 +301,10 @@ private static StringBuilder getTagIdAndChildrenIds(Tags tag) {

private static StringBuilder getTagNameAndChildrenNames(Tags tag) {
StringBuilder builder = new StringBuilder();
builder.append("'").append(tag.getTagName()).append("'");
builder.append('"').append(tag.getTagName()).append('"');

for (Tags child : tag.getChildren()) {
builder.append("," + getTagNameAndChildrenNames(child));
builder.append(",").append(getTagNameAndChildrenNames(child));
}
return builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,10 @@ public void testGetTagIdAndChildrenIds() {
tag2.setParentId(tag.getParentId());
tagsDirector.addTag(tag);
String idsStr = tagsDirector.getTagIdAndChildrenIds(tag.getTagId());
String[] ids = idsStr.split("[,]");
String[] ids = idsStr.split(",");
assertEquals(2, ids.length);
assertEquals(ids[0], "'" + tag.getTagId().toString() + "'");
assertEquals(ids[1], "'" + tag2.getTagId().toString() + "'");
assertEquals('"' + tag.getTagId().toString() + '"', ids[0]);
assertEquals('"' + tag2.getTagId().toString() + '"', ids[1]);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ public interface ITagsHandler {
String getTagNameAndChildrenNames(Guid tagId);

String getTagNamesAndChildrenNamesByRegExp(String tagNameRegExp);

String getTagsNamesByRegExp(String tagNameRegExp);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@
import java.util.stream.Collectors;

import org.ovirt.engine.core.common.businessentities.DateEnumForSearch;
import org.ovirt.engine.core.common.businessentities.Tags;
import org.ovirt.engine.core.common.config.Config;
import org.ovirt.engine.core.common.config.ConfigValues;
import org.ovirt.engine.core.common.interfaces.ITagsHandler;
import org.ovirt.engine.core.common.utils.Pair;
import org.ovirt.engine.core.compat.DateTime;
import org.ovirt.engine.core.compat.DayOfWeek;
import org.ovirt.engine.core.compat.Guid;
import org.ovirt.engine.core.compat.IntegerCompat;
import org.ovirt.engine.core.compat.Regex;
import org.ovirt.engine.core.compat.StringFormat;
Expand All @@ -32,6 +30,13 @@
*/
public class BaseConditionFieldAutoCompleter extends BaseAutoCompleter implements IConditionFieldAutoCompleter {

/**
* Stores sql expression mappers for free text search.
* key: column type
* value: sql expression mapper
*/
private static final Map<Class<?>, FreeSearchMapper> freeTextSearchMappers;

protected final Map<String, List<ValueValidationFunction>> validationDict = new HashMap<>();
private final Map<String, Class<?>> typeDict = new HashMap<>();
protected final Map<String, String> columnNameDict = new HashMap<>();
Expand All @@ -43,6 +48,16 @@ public class BaseConditionFieldAutoCompleter extends BaseAutoCompleter implement
protected final List<String> notFreeTextSearchableFieldsList = new ArrayList<>();
protected Set<String> verbsWithMultipleValues = new HashSet<>();

static {
freeTextSearchMappers = new HashMap<>();
freeTextSearchMappers.put(String.class, (table, column, relation, value) ->
StringFormat.format(" %1$s.%2$s %3$s %4$s", table, column, relation, value));
freeTextSearchMappers.put(String[].class, (table, column, relation, value) ->
StringFormat.format(
" (select bool_or(is_match_rows) from (select unnest(%1$s.%2$s) %3$s %4$s as is_match_rows))",
table, column, relation, value));
}

/**
* Gets the LIKE clause syntax for non case-sensitive search
*
Expand Down Expand Up @@ -169,8 +184,11 @@ public final String buildFreeTextConditionSql(String tableName,
}

return columnNameDict.entrySet().stream().sorted(Map.Entry.comparingByValue())
.filter(e -> typeDict.get(e.getKey()) == String.class && !notFreeTextSearchableFieldsList.contains(e.getKey()))
.map(e -> StringFormat.format(" %1$s.%2$s %3$s %4$s", tableName, e.getValue(), rel, val))
.filter(e ->
freeTextSearchMappers.containsKey(typeDict.get(e.getKey())) &&
!notFreeTextSearchableFieldsList.contains(e.getKey()))
.map(e ->
freeTextSearchMappers.get(typeDict.get(e.getKey())).map(tableName, e.getValue(), rel, val))
.distinct()
.collect(Collectors.joining(" OR ", " ( ", " ) "));
}
Expand Down Expand Up @@ -282,30 +300,39 @@ public void formatValue(String fieldName, Pair<String, String> pair, boolean cas

} else if ("TAG".equals(fieldName)) {
pair.setSecond(pair.getSecond().startsWith("N'") ? pair.getSecond().substring(2) : pair.getSecond());
if (pair.getFirst() != null && pair.getFirst().equals("=")) {
pair.setFirst("IN");
pair.setSecond(StringHelper.trim(pair.getSecond(), '\''));
Tags tag = tagsHandler.getTagByTagName(pair.getSecond());
if (tag != null) {
pair.setSecond(
StringFormat.format("(%1$s)", tagsHandler.getTagNameAndChildrenNames(tag.getTagId())));
} else {
pair.setSecond(StringFormat.format("('%1$s')", Guid.Empty));
}
} else if (pair.getFirst() != null && (pair.getFirst().equals("LIKE") || pair.getFirst().equals("ILIKE"))) {
pair.setFirst("IN");
pair.setSecond(StringHelper.trim(pair.getSecond(), '\'').replace("%", "*"));

String IDs = tagsHandler.getTagNamesAndChildrenNamesByRegExp(pair.getSecond());
if (StringHelper.isNullOrEmpty(IDs)) {
pair.setSecond(StringFormat.format("('%1$s')", Guid.Empty));
} else {
pair.setSecond(StringFormat.format("(%1$s)", IDs));
}
pair.setSecond(StringHelper.trim(pair.getSecond(), '\'').replace("%", "*"));

String tags = getMatchingTagsForRelation(pair.getSecond(), pair.getFirst());
if (StringHelper.isNullOrEmpty(tags)) {
pair.setSecond("'{}'");
} else {
pair.setSecond(StringFormat.format("'{%1$s}'", tags));
}
}
}

/**
* Retrieves tags that match the specified regular expression based on the given relation.
* The method utilises operations according to {@link StringConditionRelationAutoCompleter},
* which is used in the operation defining methods of other classes,
* such as {@link VmConditionFieldAutoCompleter#getFieldRelationshipAutoCompleter(String)}, for tags.
*
* @param tagSearchString A regular expression string used to search for tags.
* @param relation Relation for tag matching.
* Supported values: "=" for matches and "!=" for excludes.
* @return A comma-separated string of matching tag names. If no tags match, an empty string is returned.
*
* @see StringConditionRelationAutoCompleter
*/
private String getMatchingTagsForRelation(String tagSearchString, String relation) {
if ("=".equals(relation)) {
return tagsHandler.getTagNamesAndChildrenNamesByRegExp(tagSearchString);
} else {
return tagsHandler.getTagsNamesByRegExp(tagSearchString);
}
}

// private static final String DATE_FORMAT = "MMM dd,yyyy";
private static DateTime dealWithDateEnum(String value) {
DateTime formatedValue = new DateTime();
Expand Down Expand Up @@ -362,8 +389,16 @@ public String buildConditionSql(String objName, String fieldName, String customi
tableName,
getDbFieldName(fieldName));
}

String formatString;
if (isOperatorNegative(pair.getFirst())) {
if (String[].class == getTypeDictionary().get(fieldName)) {
if ("=".equals(pair.getFirst())) {
formatString = " (%1$s.%2$s IS NOT NULL AND (%1$s.%2$s %3$s %4$s)) ";
} else {
formatString = " (%1$s.%2$s IS NULL OR NOT (%1$s.%2$s %3$s %4$s)) ";
}
pair.setFirst("&&");
} else if (isOperatorNegative(pair.getFirst())) {
formatString = " (%1$s.%2$s IS NULL OR %1$s.%2$s %3$s %4$s) ";
} else {
formatString = " %1$s.%2$s %3$s %4$s ";
Expand All @@ -389,4 +424,14 @@ private static boolean isOperatorNegative(String operator) {
public String getWildcard(String fieldName) {
return verbsWithMultipleValues.contains(fieldName) ? ".*" : "%";
}

/**
* Declares free text search mapping function.
*/
private interface FreeSearchMapper {

String map(String table, String column, String relation, String value);

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public VdcUserConditionFieldAutoCompleter() {
getTypeDictionary().put(LOGIN, String.class);
getTypeDictionary().put(DIRECTORY, String.class);
getTypeDictionary().put(DEPARTMENT, String.class);
getTypeDictionary().put(TAG, String.class);
getTypeDictionary().put(TAG, String[].class);
getTypeDictionary().put(POOL, String.class);
getTypeDictionary().put(TYPE, UserOrGroup.class);

Expand All @@ -55,7 +55,7 @@ public VdcUserConditionFieldAutoCompleter() {
columnNameDict.put(LOGIN, "username");
columnNameDict.put(DIRECTORY, "domain");
columnNameDict.put(DEPARTMENT, "department");
columnNameDict.put(TAG, "tag_name");
columnNameDict.put(TAG, "tag_names");
columnNameDict.put(POOL, "vm_pool_name");
columnNameDict.put(TYPE, "user_group");
// Building the validation dict
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public VdsConditionFieldAutoCompleter() {
getTypeDictionary().put(ACTIVE_VMS, Integer.class);
getTypeDictionary().put(MIGRATING_VMS, Integer.class);
getTypeDictionary().put(COMMITTED_MEM, Integer.class);
getTypeDictionary().put(TAG, String.class);
getTypeDictionary().put(TAG, String[].class);
getTypeDictionary().put(TYPE, VDSNiceType.class);
getTypeDictionary().put(DATACENTER, String.class);
getTypeDictionary().put("ID", UUID.class);
Expand Down Expand Up @@ -115,7 +115,7 @@ public VdsConditionFieldAutoCompleter() {
columnNameDict.put(ACTIVE_VMS, "vm_active");
columnNameDict.put(MIGRATING_VMS, "vm_migrating");
columnNameDict.put(COMMITTED_MEM, "mem_commited");
columnNameDict.put(TAG, "tag_name");
columnNameDict.put(TAG, "tag_names");
columnNameDict.put(TYPE, "vds_type");
columnNameDict.put(DATACENTER, "storage_pool_name");
columnNameDict.put("ID", "vds_id");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public VmConditionFieldAutoCompleter() {
getTypeDictionary().put(CLUSTER, String.class);
getTypeDictionary().put(POOL, String.class);
getTypeDictionary().put(LOGGEDINUSER, String.class);
getTypeDictionary().put(TAG, String.class);
getTypeDictionary().put(TAG, String[].class);
getTypeDictionary().put(DATACENTER, String.class);
getTypeDictionary().put(TYPE, VmType.class);
getTypeDictionary().put(QUOTA, String.class);
Expand Down Expand Up @@ -155,7 +155,7 @@ public VmConditionFieldAutoCompleter() {
columnNameDict.put(CLUSTER, "cluster_name");
columnNameDict.put(POOL, "vm_pool_name");
columnNameDict.put(LOGGEDINUSER, "guest_cur_user_name");
columnNameDict.put(TAG, "tag_name");
columnNameDict.put(TAG, "tag_names");
columnNameDict.put(DATACENTER, "storage_pool_name");
columnNameDict.put(TYPE, "vm_type");
columnNameDict.put(QUOTA, "quota_name");
Expand Down
Loading