/* * Copyright (c) 2010-2016 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.evolveum.midpoint.prism.query; import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.match.MatchingRule; import com.evolveum.midpoint.prism.match.MatchingRuleRegistry; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.util.exception.SchemaException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.xml.namespace.QName; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.regex.Pattern; public class SubstringFilter<T> extends PropertyValueFilter<T> { private boolean anchorStart; private boolean anchorEnd; public SubstringFilter(@NotNull ItemPath path, @Nullable PrismPropertyDefinition<T> definition, @Nullable QName matchingRule, @Nullable List<PrismPropertyValue<T>> prismPropertyValues, @Nullable ExpressionWrapper expression, boolean anchorStart, boolean anchorEnd) { super(path, definition, matchingRule, prismPropertyValues, expression, null, null); this.anchorStart = anchorStart; this.anchorEnd = anchorEnd; } /** * Creates a substring filter. * * @param itemDefinition TODO about nullability * @param anyValue real value or prism property value; TODO about nullability */ public static <T> SubstringFilter<T> createSubstring(@NotNull ItemPath path, @Nullable PrismPropertyDefinition<T> itemDefinition, @NotNull PrismContext prismContext, @Nullable QName matchingRule, Object anyValue, boolean anchorStart, boolean anchorEnd) { List<PrismPropertyValue<T>> values = anyValueToPropertyValueList(prismContext, anyValue); return new SubstringFilter<>(path, itemDefinition, matchingRule, values, null, anchorStart, anchorEnd); } // TODO expression based substring filter public boolean isAnchorStart() { return anchorStart; } public boolean isAnchorEnd() { return anchorEnd; } @Override public SubstringFilter<T> clone() { return new SubstringFilter<>(getFullPath(), getDefinition(), getMatchingRule(), getClonedValues(), getExpression(), anchorStart, anchorEnd); } @Override protected String getFilterName() { return "SUBSTRING(" + (anchorStart ? "S" : "") + (anchorStart && anchorEnd ? "," : "") + (anchorEnd ? "E" : "") + ")"; } @Override public boolean match(PrismContainerValue containerValue, MatchingRuleRegistry matchingRuleRegistry) throws SchemaException { Item item = getObjectItem(containerValue); MatchingRule matching = getMatchingRuleFromRegistry(matchingRuleRegistry, item); for (Object val : item.getValues()){ if (val instanceof PrismPropertyValue){ Object value = ((PrismPropertyValue) val).getValue(); Iterator<String> iterator = (Iterator<String>) toRealValues().iterator(); while(iterator.hasNext()){ StringBuilder sb = new StringBuilder(); if (!anchorStart) { sb.append(".*"); } sb.append(Pattern.quote(iterator.next())); if (!anchorEnd) { sb.append(".*"); } if (matching.matchRegex(value, sb.toString())){ return true; } } } if (val instanceof PrismReferenceValue) { throw new UnsupportedOperationException( "matching substring on the prism reference value not supported yet"); } } return false; } private Set<T> toRealValues(){ return PrismPropertyValue.getRealValuesOfCollection(getValues()); } @Override public boolean equals(Object o, boolean exact) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o, exact)) return false; SubstringFilter<?> that = (SubstringFilter<?>) o; return anchorStart == that.anchorStart && anchorEnd == that.anchorEnd; } @Override public int hashCode() { return Objects.hash(super.hashCode(), anchorStart, anchorEnd); } }