Skip to content

Commit

Permalink
Merge branch 'master' into feature/user-search
Browse files Browse the repository at this point in the history
  • Loading branch information
1azyman committed Sep 3, 2015
2 parents 46aabfc + 3610bd4 commit 7cb1fd7
Show file tree
Hide file tree
Showing 39 changed files with 1,506 additions and 396 deletions.
Expand Up @@ -579,7 +579,7 @@ private ObjectQuery createQuery() {
DebugSearchDto dto = searchModel.getObject();

List<ObjectFilter> filters = new ArrayList<>();
if (dto.getResource() != null) {
if (ObjectTypes.SHADOW.equals(dto.getType()) && dto.getResource() != null) {
String oid = dto.getResource().getOid();
RefFilter ref = RefFilter.createReferenceEqual(ShadowType.F_RESOURCE_REF, ShadowType.class,
getPrismContext(), oid);
Expand Down
Expand Up @@ -413,7 +413,14 @@ public boolean equalsComplex(PrismPropertyValue<?> other, boolean ignoreMetadata
}

if (matchingRule != null) {
return matchingRule.match(thisRealValue, otherRealValue);
try {
return matchingRule.match(thisRealValue, otherRealValue);
} catch (SchemaException e) {
// At least one of the values is invalid. But we do not want to throw exception from
// a comparison operation. That will make the system very fragile. Let's fall back to
// ordinary equality mechanism instead.
return thisRealValue.equals(otherRealValue);
}
} else {

if (thisRealValue instanceof Element &&
Expand Down
Expand Up @@ -26,6 +26,7 @@

import com.evolveum.midpoint.prism.PrismConstants;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.exception.SchemaException;

/**
* Matching rule for LDAP distinguished name (DN).
Expand All @@ -51,7 +52,7 @@ public boolean isSupported(QName xsdType) {
* @see com.evolveum.midpoint.model.match.MatchingRule#match(java.lang.Object, java.lang.Object)
*/
@Override
public boolean match(String a, String b) {
public boolean match(String a, String b) throws SchemaException {
if (StringUtils.isBlank(a) && StringUtils.isBlank(b)) {
return true;
}
Expand All @@ -62,13 +63,13 @@ public boolean match(String a, String b) {
try {
dnA = new LdapName(a);
} catch (InvalidNameException e) {
throw new IllegalArgumentException("String '"+a+"' is not a DN: "+e.getMessage(), e);
throw new SchemaException("String '"+a+"' is not a DN: "+e.getMessage(), e);
}
LdapName dnB;
try {
dnB = new LdapName(b);
} catch (InvalidNameException e) {
throw new IllegalArgumentException("String '"+b+"' is not a DN: "+e.getMessage(), e);
throw new SchemaException("String '"+b+"' is not a DN: "+e.getMessage(), e);
}
return dnA.equals(dnB);
}
Expand All @@ -77,21 +78,21 @@ public boolean match(String a, String b) {
* @see com.evolveum.midpoint.prism.match.MatchingRule#normalize(java.lang.Object)
*/
@Override
public String normalize(String original) {
public String normalize(String original) throws SchemaException {
if (StringUtils.isBlank(original)) {
return null;
}
LdapName dn;
try {
dn = new LdapName(original);
} catch (InvalidNameException e) {
throw new IllegalArgumentException("String '"+original+"' is not a DN: "+e.getMessage(), e);
throw new SchemaException("String '"+original+"' is not a DN: "+e.getMessage(), e);
}
return StringUtils.lowerCase(dn.toString());
}

@Override
public boolean matchRegex(String a, String regex) {
public boolean matchRegex(String a, String regex) throws SchemaException {

a = normalize(a);

Expand Down
Expand Up @@ -19,6 +19,8 @@

import javax.xml.namespace.QName;

import com.evolveum.midpoint.util.exception.SchemaException;

/**
* Interface for generic matching rules. The responsibility of a matching rule is to decide if
* two objects of the same type match. This may seem a simple thing to do but the details may get
Expand All @@ -43,17 +45,17 @@ public interface MatchingRule<T> {
/**
* Matches two objects.
*/
boolean match(T a, T b);
boolean match(T a, T b) throws SchemaException;

/**
* Matches value against given regex.
*/
boolean matchRegex(T a, String regex);
boolean matchRegex(T a, String regex) throws SchemaException;

/**
* Returns a normalized version of the value.
* For normalized version the following holds:
* if A matches B then normalize(A) == normalize(B)
*/
T normalize(T original);
T normalize(T original) throws SchemaException;
}
Expand Up @@ -227,8 +227,17 @@ private boolean isInFilterItem(PrismPropertyValue v, Item filterItem, MatchingRu
}

PrismPropertyValue filterV = (PrismPropertyValue) filterValue;
if (matchingRule.match(filterV.getValue(), v.getValue())){
return true;
try {
if (matchingRule.match(filterV.getValue(), v.getValue())){
return true;
}
} catch (SchemaException e) {
// At least one of the values is invalid. But we do not want to throw exception from
// a comparison operation. That will make the system very fragile. Let's fall back to
// ordinary equality mechanism instead.
if (filterV.getValue().equals(v.getValue())) {
return true;
}
}
}

Expand Down
Expand Up @@ -735,10 +735,15 @@ public static <T> void assertValues(String message, Collection<PrismPropertyValu
}

public static <T> void assertSets(String message, Collection<T> actualValues, T... expectedValues) {
assertSets(message, null, actualValues, expectedValues);
try {
assertSets(message, null, actualValues, expectedValues);
} catch (SchemaException e) {
// no matching rule. should not happen
throw new IllegalStateException(e.getMessage(), e);
}
}

public static <T> void assertSets(String message, MatchingRule<T> matchingRule, Collection<T> actualValues, T... expectedValues) {
public static <T> void assertSets(String message, MatchingRule<T> matchingRule, Collection<T> actualValues, T... expectedValues) throws SchemaException {
assertNotNull("Null set in " + message, actualValues);
assertEquals("Wrong number of values in " + message+ "; expected (real values) "
+PrettyPrinter.prettyPrint(expectedValues)+"; has (pvalues) "+actualValues,
Expand Down Expand Up @@ -901,7 +906,7 @@ public static void assertEquals(String message, Object expected, Object actual)
+ ", was " + MiscUtil.getValueWithClass(actual);
}

public static <T> void assertEquals(String message, MatchingRule<T> matchingRule, T expected, T actual) {
public static <T> void assertEquals(String message, MatchingRule<T> matchingRule, T expected, T actual) throws SchemaException {
assert equals(matchingRule, expected, actual) : message
+ ": expected " + MiscUtil.getValueWithClass(expected)
+ ", was " + MiscUtil.getValueWithClass(actual);
Expand All @@ -917,7 +922,7 @@ static void fail(String message) {
assert false: message;
}

private static <T> boolean equals(MatchingRule<T> matchingRule, T a, T b) {
private static <T> boolean equals(MatchingRule<T> matchingRule, T a, T b) throws SchemaException {
if (a == null && b == null) {
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions infra/prism/src/main/resources/xml/ns/public/query-3.xsd
Expand Up @@ -32,7 +32,7 @@
<xsd:documentation>
TODO

Version: 3.1
Version: 3.3-SNAPSHOT
Recommended namespace prefix: q
</xsd:documentation>
</xsd:annotation>
Expand Down Expand Up @@ -175,7 +175,7 @@
</xsd:annotation>
<xsd:sequence>
<xsd:element name="description" type="xsd:string" minOccurs="0" maxOccurs="1"/>
<xsd:element name="filter" type="tns:SearchFilterType"/>
<xsd:element name="filter" type="tns:SearchFilterType" minOccurs="0"/>
<xsd:element name="paging" type="tns:PagingType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
Expand Down
Expand Up @@ -118,15 +118,15 @@ public void testPolyStringNorm() throws Exception {
assertNoMatch(rule, new PolyString("Bar", "bar"), new PolyString("Bar", "barbar"));
}

private <T> void assertMatch(MatchingRule<T> rule, T a, T b) {
private <T> void assertMatch(MatchingRule<T> rule, T a, T b) throws SchemaException {
assertTrue("Values '"+a+"' and '"+b+"' does not match; rule: "+rule, rule.match(a, b));
}

private <T> void assertNoMatch(MatchingRule<T> rule, T a, T b) {
private <T> void assertNoMatch(MatchingRule<T> rule, T a, T b) throws SchemaException {
assertFalse("Values '"+a+"' and '"+b+"' DOES match but they should not; rule: "+rule, rule.match(a, b));
}

private void assertNormalized(MatchingRule<String> rule, String expected, String original) {
private void assertNormalized(MatchingRule<String> rule, String expected, String original) throws SchemaException {
assertEquals("Normalized value does not match", expected, rule.normalize(original));
}
}
Expand Up @@ -191,6 +191,7 @@ public abstract class SchemaConstants {

public static final QName MODEL_EXTENSION_DIAGNOSE = new QName(NS_MODEL_EXTENSION, "diagnose");
public static final QName MODEL_EXTENSION_FIX = new QName(NS_MODEL_EXTENSION, "fix");
public static final QName MODEL_EXTENSION_DUPLICATE_SHADOWS_RESOLVER = new QName(NS_MODEL_EXTENSION, "duplicateShadowsResolver");

public static final String NS_GUI = NS_MIDPOINT_PUBLIC + "/gui";
public static final String NS_GUI_CHANNEL = NS_GUI + "/channels-3";
Expand Down
Expand Up @@ -224,7 +224,19 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:element>


<xsd:element name="duplicateShadowsResolver" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
Class that is used to resolve duplicate shadows in ShadowIntegrityCheck task.
If not specified, a default implementation is used.
</xsd:documentation>
<xsd:appinfo>
<a:maxOccurs>1</a:maxOccurs>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>

</xsd:schema>


Expand Up @@ -17,6 +17,7 @@

import java.io.File;
import java.io.IOException;
import java.text.Normalizer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
Expand Down Expand Up @@ -196,6 +197,14 @@ public String norm(PolyStringType orig) {
return norm(polyString);
}

public String toAscii(Object input) {
if (input == null) {
return null;
}
String inputString = stringify(input);
String decomposed = Normalizer.normalize(inputString, Normalizer.Form.NFKD);
return decomposed.replaceAll("\\p{M}", "");
}

/**
* Converts whatever it gets to a string. But it does it in a sensitive way.
Expand All @@ -208,6 +217,18 @@ public String stringify(Object whatever) {
return "";
}

if (whatever instanceof String) {
return (String)whatever;
}

if (whatever instanceof PolyString) {
return ((PolyString)whatever).getOrig();
}

if (whatever instanceof PolyStringType) {
return ((PolyStringType)whatever).getOrig();
}

if (whatever instanceof Collection) {
Collection collection = (Collection)whatever;
if (collection.isEmpty()) {
Expand Down
Expand Up @@ -421,4 +421,19 @@ private PolyString poly(String s) {
return PrismTestUtil.createPolyString(s);
}

@Test
public void testToAscii() throws Exception {
final String TEST_NAME = "testToAscii";
TestUtil.displayTestTile(TEST_NAME);
BasicExpressionFunctions basic = createBasicFunctions();
assertEquals("foo", basic.toAscii("foo"));
assertEquals("foo", basic.toAscii(poly("foo")));
assertEquals("foo", basic.toAscii(PrismTestUtil.createPolyStringType("foo")));
assertEquals("Cortuv hrad, tam Strasa!", basic.toAscii("Čórtův hrád, tam Strašá!"));
assertEquals("hrabe Teleke z Toloko", basic.toAscii(poly("hrabě Teleke z Tölökö")));
assertEquals("Vedeckotechnicka revoluce neni zadna idyla!", basic.toAscii(PrismTestUtil.createPolyStringType("Vědeckotechnická revoluce není žádná idyla!")));
assertEquals(null, basic.toAscii(null));
assertEquals("", basic.toAscii(""));
}

}
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2010-2015 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.model.impl.integrity;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.SynchronizationSituationType;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* @author Pavol Mederly
*/
public class DefaultDuplicateShadowsResolver implements DuplicateShadowsResolver {

static final Trace LOGGER = TraceManager.getTrace(DefaultDuplicateShadowsResolver.class);

@Override
public DuplicateShadowsTreatmentInstruction determineDuplicateShadowsTreatment(Collection<PrismObject<ShadowType>> shadows) {
if (shadows.size() <= 1) {
return null;
}
LOGGER.trace("Determining duplicate shadows treatment: conflicting set with {} members", shadows.size());
// prefer shadows with intent and linked ones
int bestScore = 0;
PrismObject<ShadowType> bestShadow = null;
for (PrismObject<ShadowType> shadow : shadows) {
ShadowType shadowType = shadow.asObjectable();
int score = 0;
if (shadowType.getSynchronizationSituation() == SynchronizationSituationType.LINKED) {
score += 10;
}
List owners = (List) shadow.getUserData(ShadowIntegrityCheckResultHandler.KEY_OWNERS);
if (owners != null && !owners.isEmpty()) {
score += 10;
}
if (shadowType.getIntent() != null && !shadowType.getIntent().isEmpty()) {
score += 8;
}
if (shadow.getUserData(ShadowIntegrityCheckResultHandler.KEY_EXISTS_ON_RESOURCE) != null) { // filled in only if checkFetch is true
score += 50;
}
LOGGER.trace("Shadow {} has score of {}; best is {}", ObjectTypeUtil.toShortString(shadow), score, bestScore);
if (bestShadow == null || score > bestScore) {
bestScore = score;
bestShadow = shadow;
}
}
DuplicateShadowsTreatmentInstruction instruction = new DuplicateShadowsTreatmentInstruction();
instruction.setShadowOidToReplaceDeletedOnes(bestShadow.getOid());
instruction.setShadowsToDelete(new ArrayList<PrismObject<ShadowType>>());
for (PrismObject<ShadowType> shadow : shadows) {
if (!shadow.getOid().equals(bestShadow.getOid())) {
instruction.getShadowsToDelete().add(shadow);
}
}
return instruction;
}
}

0 comments on commit 7cb1fd7

Please sign in to comment.