[prev in list] [next in list] [prev in thread] [next in thread] 

List:       forgerock-openidm-commit
Subject:    [CommitOpenIDM] [5038] trunk: OPENIDM-2896/ OPENIDM-3053 CR-6432 Replace linkQualifier with queryFil
From:       anonymous () forgerock ! org
Date:       2015-03-23 19:18:59
Message-ID: 20150323191859.112D33F865 () sources ! internal ! forgerock ! com
[Download RAW message or body]

[Attachment #2 (text/html)]

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[5038] trunk: OPENIDM-2896/OPENIDM-3053 CR-6432 Replace linkQualifier with \
queryFilter in Conditions, use linkQualifiers to filter effectiveAssignments</title> \
</head> <body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: \
verdana,arial,helvetica,sans-serif; font-size: 10pt;  } #msg dl a { font-weight: \
bold} #msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: \
bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: \
6px; } #logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em \
0; } #logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg \
h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; } \
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; \
} #logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: \
-1.5em; padding-left: 1.5em; } #logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em \
1em 0 1em; background: white;} #logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid \
#fa0; border-bottom: 1px solid #fa0; background: #fff; } #logmsg table th { \
text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted \
#fa0; } #logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: \
0.2em 0.5em; } #logmsg table thead th { text-align: center; border-bottom: 1px solid \
#fa0; } #logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: \
6px; } #patch { width: 100%; }
#patch h4 {font-family: \
verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
 #patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, \
#patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins \
{background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del \
{background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, \
                .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a \
href="http://sources.forgerock.org/changelog/openidm/?cs=5038">5038</a></dd> \
<dt>Author</dt> <dd>jbranch</dd> <dt>Date</dt> <dd>2015-03-23 19:18:58 +0000 (Mon, 23 \
Mar 2015)</dd> </dl>

<h3>Log Message</h3>
<pre><a href="https://bugster.forgerock.org/jira/browse/OPENIDM-2896">OPENIDM-2896</a>/<a \
href="https://bugster.forgerock.org/jira/browse/OPENIDM-3053">OPENIDM-3053</a> \
CR-6432 Replace linkQualifier with queryFilter in Conditions, use linkQualifiers to \
filter effectiveAssignments</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkopenidmcoresrcmainjavaorgforgerockopenidmsyncimplConditionjava">tru \
nk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/Condition.java</a></li> \
<li><a href="#trunkopenidmcoresrcmainjavaorgforgerockopenidmsyncimplObjectMappingjava" \
>trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/ObjectMapping.java</a></li>
> 
<li><a href="#trunkopenidmcoresrcmainjavaorgforgerockopenidmsyncimplPropertyMappingjav \
a">trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/PropertyMapping.java</a></li>
 <li><a href="#trunkopenidmcoresrctestjavaorgforgerockopenidmsyncimplPolicyTestjava">t \
runk/openidm-core/src/test/java/org/forgerock/openidm/sync/impl/PolicyTest.java</a></li>
 <li><a href="#trunkopenidmcoresrctestresourcesconfsyncjson">trunk/openidm-core/src/test/resources/conf/sync.json</a></li>
 <li><a href="#trunkopenidmzipsrcmainresourcesbindefaultsscriptrolesdefaultMappingjs"> \
trunk/openidm-zip/src/main/resources/bin/defaults/script/roles/defaultMapping.js</a></li>
 </ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkopenidmcoresrctestjavaorgforgerockopenidmsyncimplConditionTestjava" \
>trunk/openidm-core/src/test/java/org/forgerock/openidm/sync/impl/ConditionTest.java</a></li>
> 
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkopenidmcoresrcmainjavaorgforgerockopenidmsyncimplConditionjava"></a>
<div class="modfile"><h4>Modified: \
trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/Condition.java (5037 \
=> 5038)</h4> <pre class="diff"><span>
<span class="info">--- \
trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/Condition.java	2015-03-23 \
                17:51:23 UTC (rev 5037)
+++ trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/Condition.java	2015-03-23 \
19:18:58 UTC (rev 5038) </span><span class="lines">@@ -23,17 +23,23 @@
</span><span class="cx">  */
</span><span class="cx"> package org.forgerock.openidm.sync.impl;
</span><span class="cx"> 
</span><del>-import java.util.HashMap;
-import java.util.Map;
-
</del><span class="cx"> import javax.script.ScriptException;
</span><span class="cx"> 
</span><ins>+import org.forgerock.json.fluent.JsonPointer;
</ins><span class="cx"> import org.forgerock.json.fluent.JsonValue;
</span><span class="cx"> import org.forgerock.json.fluent.JsonValueException;
</span><ins>+import org.forgerock.json.resource.QueryFilter;
+import org.forgerock.json.resource.QueryFilterVisitor;
</ins><span class="cx"> import org.forgerock.openidm.sync.impl.Scripts.Script;
</span><span class="cx"> import org.slf4j.Logger;
</span><span class="cx"> import org.slf4j.LoggerFactory;
</span><span class="cx"> 
</span><ins>+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
</ins><span class="cx"> /**
</span><span class="cx">  * Represents a condition on which a property mapping may be \
applied, or a policy may be enforced. </span><span class="cx">  */
</span><span class="lines">@@ -53,9 +59,9 @@
</span><span class="cx">          */
</span><span class="cx">         SCRIPTED,
</span><span class="cx">         /**
</span><del>-         * A condition evaluated by a matching \
&quot;linkQualifier&quot;. </del><ins>+         * A condition evaluated by a matching \
&quot;queryFilter&quot;. </ins><span class="cx">          */
</span><del>-        LINK_QUALIFIER,
</del><ins>+        QUERY_FILTER,
</ins><span class="cx">         /**
</span><span class="cx">          * A condition which always passes. This is used if \
a null configuration is passed in. </span><span class="cx">          */
</span><span class="lines">@@ -68,9 +74,9 @@
</span><span class="cx">     private Type type;
</span><span class="cx">     
</span><span class="cx">     /**
</span><del>-     * The link qualifier if configured
</del><ins>+     * The query filter if configured
</ins><span class="cx">      */
</span><del>-    private String linkQualifier;
</del><ins>+    private QueryFilter queryFilter;
</ins><span class="cx">     
</span><span class="cx">     /**
</span><span class="cx">      * The condition script if configured
</span><span class="lines">@@ -85,8 +91,8 @@
</span><span class="cx">     public Condition(JsonValue config) {
</span><span class="cx">         if (config.isNull()) {
</span><span class="cx">             init(Type.TRUE, null, null);
</span><del>-        } else if \
                (config.asMap().containsKey(&quot;linkQualifier&quot;)) {
-            init(Type.LINK_QUALIFIER, \
config.get(&quot;linkQualifier&quot;).asString(), null); </del><ins>+        } else \
if (config.get(&quot;filter&quot;) != null) { +            init(Type.QUERY_FILTER, \
QueryFilter.valueOf(config.get(&quot;filter&quot;).asString()), null); </ins><span \
class="cx">         } else { </span><span class="cx">             init(Type.SCRIPTED, \
null, Scripts.newInstance(config)); </span><span class="cx">         }
</span><span class="lines">@@ -96,12 +102,12 @@
</span><span class="cx">      * Initializes the condition fields.
</span><span class="cx">      * 
</span><span class="cx">      * @param type the conditions type.
</span><del>-     * @param linkQualifier the link qualifier.
</del><ins>+     * @param queryFilter the query filter.
</ins><span class="cx">      * @param script the condition script.
</span><span class="cx">      */
</span><del>-    private void init(Type type, String linkQualifier, Script script) {
</del><ins>+    private void init(Type type, QueryFilter queryFilter, Script script) \
{ </ins><span class="cx">         this.type = type;
</span><del>-        this.linkQualifier = linkQualifier;
</del><ins>+        this.queryFilter = queryFilter;
</ins><span class="cx">         this.script = script;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -109,20 +115,18 @@
</span><span class="cx">      * Evaluates the condition.  Returns true if the \
condition is met, false otherwise. </span><span class="cx">      * 
</span><span class="cx">      * @param params parameters to use during evaluation.
</span><del>-     * @param linkQualifier the link qualifier associated with the \
current sync </del><span class="cx">      * @return true if the condition is met, \
false otherwise. </span><span class="cx">      * @throws SynchronizationException if \
errors are encountered. </span><span class="cx">      */
</span><del>-    public boolean evaluate(JsonValue params, String linkQualifier) 
</del><ins>+    public boolean evaluate(JsonValue params)
</ins><span class="cx">             throws SynchronizationException {
</span><span class="cx">         switch (type) {
</span><span class="cx">         case TRUE:
</span><span class="cx">             return true;
</span><del>-        case LINK_QUALIFIER:
-            return this.linkQualifier.equals(linkQualifier);
</del><ins>+        case QUERY_FILTER:
+            return queryFilter == null ? false : \
queryFilter.accept(JSONVALUE_FILTER_VISITOR, params); </ins><span class="cx">         \
case SCRIPTED: </span><span class="cx">             Map&lt;String, Object&gt; scope = \
new HashMap&lt;String, Object&gt;(); </span><del>-            \
scope.put(&quot;linkQualifier&quot;, linkQualifier); </del><span class="cx">          \
try { </span><span class="cx">                 if (params.isMap()) {
</span><span class="cx">                     scope.putAll(params.asMap());
</span><span class="lines">@@ -143,4 +147,194 @@
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
+    /**
+     * This is a relatively generic implementation for testing JsonValue objects \
though it +     * only returns Boolean for the test result.  This may be extractable \
to a more common +     * location for broader use.
+     */
+    private static final QueryFilterVisitor&lt;Boolean, JsonValue&gt; \
JSONVALUE_FILTER_VISITOR = +            new QueryFilterVisitor&lt;Boolean, \
JsonValue&gt;() { +
+                @Override
+                public Boolean visitAndFilter(final JsonValue p, final \
List&lt;QueryFilter&gt; subFilters) { +                    for (final QueryFilter \
subFilter : subFilters) { +                        if (!subFilter.accept(this, p)) {
+                            return Boolean.FALSE;
+                        }
+                    }
+                    return Boolean.TRUE;
+                }
+
+                @Override
+                public Boolean visitBooleanLiteralFilter(final JsonValue p, final \
boolean value) { +                    return value;
+                }
+
+                @Override
+                public Boolean visitContainsFilter(final JsonValue p, final \
JsonPointer field, +                                                   final Object \
valueAssertion) { +                    for (final Object value : getValues(p, field)) \
{ +                        if (isCompatible(valueAssertion, value)) {
+                            if (valueAssertion instanceof String) {
+                                final String s1 = ((String) \
valueAssertion).toLowerCase(Locale.ENGLISH); +                                final \
String s2 = ((String) value).toLowerCase(Locale.ENGLISH); +                           \
if (s2.contains(s1)) { +                                    return Boolean.TRUE;
+                                }
+                            } else {
+                                // Use equality matching for numbers and booleans.
+                                if (compareValues(valueAssertion, value) == 0) {
+                                    return Boolean.TRUE;
+                                }
+                            }
+                        }
+                    }
+                    return Boolean.FALSE;
+                }
+
+                @Override
+                public Boolean visitEqualsFilter(final JsonValue p, final \
JsonPointer field, +                                                 final Object \
valueAssertion) { +                    Boolean result = Boolean.TRUE;
+                    for (final Object value : getValues(p, field)) {
+                        if (!isCompatible(valueAssertion, value) || \
compareValues(valueAssertion, value) != 0) { +                            result = \
Boolean.FALSE; +                        }
+                    }
+                    return result;
+                }
+
+                @Override
+                public Boolean visitExtendedMatchFilter(final JsonValue p, final \
JsonPointer field, +                                                        final \
String matchingRuleId, final Object valueAssertion) { +                    // \
Extended filters are not supported +                    return Boolean.FALSE;
+                }
+
+                @Override
+                public Boolean visitGreaterThanFilter(final JsonValue p, final \
JsonPointer field, +                                                      final \
Object valueAssertion) { +                    for (final Object value : getValues(p, \
field)) { +                        if (isCompatible(valueAssertion, value) &amp;&amp; \
compareValues(valueAssertion, value) &lt; 0) { +                            return \
Boolean.TRUE; +                        }
+                    }
+                    return Boolean.FALSE;
+                }
+
+                @Override
+                public Boolean visitGreaterThanOrEqualToFilter(final JsonValue p, \
final JsonPointer field, +                                                            \
final Object valueAssertion) { +                    for (final Object value : \
getValues(p, field)) { +                        if (isCompatible(valueAssertion, \
value) &amp;&amp; compareValues(valueAssertion, value) &lt;= 0) { +                   \
return Boolean.TRUE; +                        }
+                    }
+                    return Boolean.FALSE;
+                }
+
+                @Override
+                public Boolean visitLessThanFilter(final JsonValue p, final \
JsonPointer field, +                                                   final Object \
valueAssertion) { +                    for (final Object value : getValues(p, field)) \
{ +                        if (isCompatible(valueAssertion, value) &amp;&amp; \
compareValues(valueAssertion, value) &gt; 0) { +                            return \
Boolean.TRUE; +                        }
+                    }
+                    return Boolean.FALSE;
+                }
+
+                @Override
+                public Boolean visitLessThanOrEqualToFilter(final JsonValue p, final \
JsonPointer field, +                                                            final \
Object valueAssertion) { +                    for (final Object value : getValues(p, \
field)) { +                        if (isCompatible(valueAssertion, value) &amp;&amp; \
compareValues(valueAssertion, value) &gt;= 0) { +                            return \
Boolean.TRUE; +                        }
+                    }
+                    return Boolean.FALSE;
+                }
+
+                @Override
+                public Boolean visitNotFilter(final JsonValue p, final QueryFilter \
subFilter) { +                    return !subFilter.accept(this, p);
+                }
+
+                @Override
+                public Boolean visitOrFilter(final JsonValue p, final \
List&lt;QueryFilter&gt; subFilters) { +                    for (final QueryFilter \
subFilter : subFilters) { +                        if (subFilter.accept(this, p)) {
+                            return Boolean.TRUE;
+                        }
+                    }
+                    return Boolean.FALSE;
+                }
+
+                @Override
+                public Boolean visitPresentFilter(final JsonValue p, final \
JsonPointer field) { +                    final JsonValue value = p.get(field);
+                    return value != null;
+                }
+
+                @Override
+                public Boolean visitStartsWithFilter(final JsonValue p, final \
JsonPointer field, +                                                     final Object \
valueAssertion) { +                    for (final Object value : getValues(p, field)) \
{ +                        if (isCompatible(valueAssertion, value)) {
+                            if (valueAssertion instanceof String) {
+                                final String s1 = ((String) \
valueAssertion).toLowerCase(Locale.ENGLISH); +                                final \
String s2 = ((String) value).toLowerCase(Locale.ENGLISH); +                           \
if (s2.startsWith(s1)) { +                                    return Boolean.TRUE;
+                                }
+                            } else {
+                                // Use equality matching for numbers and booleans.
+                                if (compareValues(valueAssertion, value) == 0) {
+                                    return Boolean.TRUE;
+                                }
+                            }
+                        }
+                    }
+                    return Boolean.FALSE;
+                }
+
+                private List&lt;Object&gt; getValues(final JsonValue resource, final \
JsonPointer field) { +                    final JsonValue value = \
resource.get(field); +                    if (value == null) {
+                        return Collections.emptyList();
+                    } else if (value.isList()) {
+                        return value.asList();
+                    } else {
+                        return Collections.singletonList(value.getObject());
+                    }
+                }
+
+            };
+
+    private static int compareValues(final Object v1, final Object v2) {
+        if (v1 instanceof String &amp;&amp; v2 instanceof String) {
+            final String s1 = (String) v1;
+            final String s2 = (String) v2;
+            return s1.compareToIgnoreCase(s2);
+        } else if (v1 instanceof Number &amp;&amp; v2 instanceof Number) {
+            final Double n1 = ((Number) v1).doubleValue();
+            final Double n2 = ((Number) v2).doubleValue();
+            return n1.compareTo(n2);
+        } else if (v1 instanceof Boolean &amp;&amp; v2 instanceof Boolean) {
+            final Boolean b1 = (Boolean) v1;
+            final Boolean b2 = (Boolean) v2;
+            return b1.compareTo(b2);
+        } else {
+            // Different types: we need to ensure predictable ordering,
+            // so use class name as secondary key.
+            return v1.getClass().getName().compareTo(v2.getClass().getName());
+        }
+    }
+
+    private static boolean isCompatible(final Object v1, final Object v2) {
+        return (v1 instanceof String &amp;&amp; v2 instanceof String)
+                || (v1 instanceof Number &amp;&amp; v2 instanceof Number)
+                || (v1 instanceof Boolean &amp;&amp; v2 instanceof Boolean);
+    }
</ins><span class="cx"> }
</span></span></pre></div>
<a id="trunkopenidmcoresrcmainjavaorgforgerockopenidmsyncimplObjectMappingjava"></a>
<div class="modfile"><h4>Modified: \
trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/ObjectMapping.java \
(5037 => 5038)</h4> <pre class="diff"><span>
<span class="info">--- \
trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/ObjectMapping.java	2015-03-23 \
                17:51:23 UTC (rev 5037)
+++ trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/ObjectMapping.java	2015-03-23 \
19:18:58 UTC (rev 5038) </span><span class="lines">@@ -666,7 +666,7 @@
</span><span class="cx">                 property.apply(source, oldSource, target, \
linkQualifier); </span><span class="cx">             }
</span><span class="cx">             // Apply default mapping, if configured
</span><del>-            applyDefaultMappings(source, oldSource, target, \
existingTarget); </del><ins>+            applyDefaultMappings(source, oldSource, \
target, existingTarget, linkQualifier); </ins><span class="cx">             
</span><span class="cx">             measure.setResult(target);
</span><span class="cx">         } finally {
</span><span class="lines">@@ -674,7 +674,7 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    private JsonValue applyDefaultMappings(JsonValue source, JsonValue \
oldSource, JsonValue target, JsonValue existingTarget) throws \
SynchronizationException { </del><ins>+    private JsonValue \
applyDefaultMappings(JsonValue source, JsonValue oldSource, JsonValue target, \
JsonValue existingTarget, String linkQualifier) throws SynchronizationException { \
</ins><span class="cx">         JsonValue result = null; </span><span class="cx">     \
if (defaultMapping != null) { </span><span class="cx">             Map&lt;String, \
Object&gt; queryScope = new HashMap&lt;String, Object&gt;(); </span><span \
class="lines">@@ -685,6 +685,7 @@ </span><span class="cx">             \
queryScope.put(&quot;target&quot;, target.asMap()); </span><span class="cx">          \
queryScope.put(&quot;config&quot;, config.asMap()); </span><span class="cx">          \
queryScope.put(&quot;existingTarget&quot;, existingTarget.asMap()); </span><ins>+     \
queryScope.put(&quot;linkQualifier&quot;, linkQualifier); </ins><span class="cx">     \
try { </span><span class="cx">                 result = \
json(defaultMapping.exec(queryScope)); </span><span class="cx">             } catch \
(ScriptThrownException ste) { </span><span class="lines">@@ -1708,7 +1709,10 @@
</span><span class="cx">                 action = situation.getDefaultAction();
</span><span class="cx">                 List&lt;Policy&gt; situationPolicies = \
getPolicies(situation); </span><span class="cx">                 for (Policy policy : \
situationPolicies) { </span><del>-                    if \
(policy.getCondition().evaluate(json(field(&quot;object&quot;, getSourceObject())), \
getLinkQualifier())) { </del><ins>+                    if \
(policy.getCondition().evaluate( +                            json(object(
+                                    field(&quot;object&quot;, getSourceObject()),
+                                    field(&quot;linkQualifier&quot;, \
getLinkQualifier()))))) { </ins><span class="cx">                         \
activePolicy = policy; </span><span class="cx">                         action = \
activePolicy.getAction(sourceObjectAccessor,  </span><span class="cx">                \
targetObjectAccessor, this, getLinkQualifier()); </span></span></pre></div>
<a id="trunkopenidmcoresrcmainjavaorgforgerockopenidmsyncimplPropertyMappingjava"></a>
 <div class="modfile"><h4>Modified: \
trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/PropertyMapping.java \
(5037 => 5038)</h4> <pre class="diff"><span>
<span class="info">--- \
trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/PropertyMapping.java	2015-03-23 \
                17:51:23 UTC (rev 5037)
+++ trunk/openidm-core/src/main/java/org/forgerock/openidm/sync/impl/PropertyMapping.java	2015-03-23 \
19:18:58 UTC (rev 5038) </span><span class="lines">@@ -170,10 +170,10 @@
</span><span class="cx">      */
</span><span class="cx">     public boolean evaluateCondition(JsonValue sourceObject, \
JsonValue oldSource, JsonValue targetObject, String linkQualifier)  </span><span \
class="cx">             throws SynchronizationException { </span><del>-        \
JsonValue params = json(object(field(&quot;object&quot;, sourceObject))); \
</del><ins>+        JsonValue params = json(object(field(&quot;object&quot;, \
sourceObject), field(&quot;linkQualifier&quot;, linkQualifier))); </ins><span \
class="cx">         if (oldSource != null) { </span><span class="cx">             \
params.put(&quot;oldSource&quot;, oldSource); </span><span class="cx">         }
</span><del>-        return condition.evaluate(params, linkQualifier);
</del><ins>+        return condition.evaluate(params);
</ins><span class="cx">     }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkopenidmcoresrctestjavaorgforgerockopenidmsyncimplConditionTestjava"></a>
<div class="addfile"><h4>Added: \
trunk/openidm-core/src/test/java/org/forgerock/openidm/sync/impl/ConditionTest.java \
(0 => 5038)</h4> <pre class="diff"><span>
<span class="info">--- \
trunk/openidm-core/src/test/java/org/forgerock/openidm/sync/impl/ConditionTest.java	  \
                (rev 0)
+++ trunk/openidm-core/src/test/java/org/forgerock/openidm/sync/impl/ConditionTest.java	2015-03-23 \
19:18:58 UTC (rev 5038) </span><span class="lines">@@ -0,0 +1,83 @@
</span><ins>+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014-2015 ForgeRock AS. All rights reserved.
+ *
+ * The contents of this file are subject to the terms
+ * of the Common Development and Distribution License
+ * (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://forgerock.org/license/CDDLv1.0.html
+ * See the License for the specific language governing
+ * permission and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL
+ * Header Notice in each file and include the License file
+ * at http://forgerock.org/license/CDDLv1.0.html
+ * If applicable, add the following below the CDDL Header,
+ * with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * &quot;Portions Copyrighted [year] [name of copyright owner]&quot;
+ */
+package org.forgerock.openidm.sync.impl;
+
+import org.forgerock.json.fluent.JsonValue;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.HashMap;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.forgerock.json.fluent.JsonValue.field;
+import static org.forgerock.json.fluent.JsonValue.json;
+import static org.forgerock.json.fluent.JsonValue.object;
+
+/**
+ * Test the Condition class.
+ *
+ * Currently only the filter visitor is tested.
+ */
+public class ConditionTest {
+    private static JsonValue testObject = json(object(
+            field(&quot;object&quot;, object(
+                field(&quot;name&quot;, &quot;alice&quot;),
+                field(&quot;age&quot;, 1234L),
+                field(&quot;balance&quot;, 3.14159),
+                field(&quot;isAdmin&quot;, false))
+            ),
+            field(&quot;linkQualifier&quot;, &quot;test&quot;)));
+
+    @DataProvider
+    public Object[][] filterData() {
+        return new Object[][] {
+                // @formatter:off
+                { &quot;/object/name eq \&quot;alice\&quot;&quot;, true },
+                { &quot;/object/age eq 1234&quot;, true },
+                { &quot;/object/balance eq 3.14159&quot;, true },
+                { &quot;/object/isAdmin eq false&quot;, true },
+                { &quot;/object/age lt 1234&quot;, false },
+                { &quot;/object/age le 1234&quot;, true },
+                { &quot;/object/age gt 1234&quot;, false },
+                { &quot;/object/age ge 1234&quot;, true },
+                { &quot;/object/name co \&quot;al\&quot;&quot;, true },
+                { &quot;/object/name sw \&quot;al\&quot;&quot;, true },
+                { &quot;/object/name pr&quot;, true },
+                { &quot;/object/age lt 18 or /object/age gt 30&quot;, true },
+                { &quot;/object/age lt 1000 or /object/age gt 3000&quot;, false },
+                { &quot;/object/age lt 18 and /object/age gt 30&quot;, false },
+                { &quot;/object/age gt 1000 and /object/age lt 1300&quot;, true },
+                { &quot;/object/age ne 1234&quot;, false },
+                { &quot;/linkQualifier eq \&quot;test\&quot;&quot;, true },
+                { &quot;/linkQualifier eq \&quot;fail\&quot;&quot;, false }
+                // @formatter:on
+        };
+    }
+
+    @Test(dataProvider = &quot;filterData&quot;)
+    public void testEvaluate(String filter, Boolean state) throws \
SynchronizationException { +        Condition testCondition = new \
Condition(json(object(field(&quot;filter&quot;, filter)))); +        \
assertThat(testCondition.evaluate(testObject)).isEqualTo(state); +    }
+}
</ins></span></pre></div>
<a id="trunkopenidmcoresrctestjavaorgforgerockopenidmsyncimplPolicyTestjava"></a>
<div class="modfile"><h4>Modified: \
trunk/openidm-core/src/test/java/org/forgerock/openidm/sync/impl/PolicyTest.java \
(5037 => 5038)</h4> <pre class="diff"><span>
<span class="info">--- \
trunk/openidm-core/src/test/java/org/forgerock/openidm/sync/impl/PolicyTest.java	2015-03-23 \
                17:51:23 UTC (rev 5037)
+++ trunk/openidm-core/src/test/java/org/forgerock/openidm/sync/impl/PolicyTest.java	2015-03-23 \
19:18:58 UTC (rev 5038) </span><span class="lines">@@ -1,3 +1,26 @@
</span><ins>+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014-2015 ForgeRock AS. All rights reserved.
+ *
+ * The contents of this file are subject to the terms
+ * of the Common Development and Distribution License
+ * (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * http://forgerock.org/license/CDDLv1.0.html
+ * See the License for the specific language governing
+ * permission and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL
+ * Header Notice in each file and include the License file
+ * at http://forgerock.org/license/CDDLv1.0.html
+ * If applicable, add the following below the CDDL Header,
+ * with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * &quot;Portions Copyrighted [year] [name of copyright owner]&quot;
+ */
</ins><span class="cx"> package org.forgerock.openidm.sync.impl;
</span><span class="cx"> 
</span><span class="cx"> import com.fasterxml.jackson.databind.ObjectMapper;
</span><span class="lines">@@ -20,6 +43,7 @@
</span><span class="cx"> import java.util.List;
</span><span class="cx"> import java.util.Map;
</span><span class="cx"> 
</span><ins>+import static org.forgerock.json.fluent.JsonValue.field;
</ins><span class="cx"> import static org.forgerock.json.fluent.JsonValue.json;
</span><span class="cx"> import static org.forgerock.json.fluent.JsonValue.object;
</span><span class="cx"> import static org.mockito.Matchers.anyMap;
</span><span class="lines">@@ -73,29 +97,29 @@
</span><span class="cx">         assertEquals(policies.size(), 8);
</span><span class="cx"> 
</span><span class="cx">         \
assertTrue(getPolicy(Situation.CONFIRMED).getCondition() </span><del>-                \
.evaluate(json(object()), Link.DEFAULT_LINK_QUALIFIER)); </del><ins>+                \
.evaluate(json(object(field(&quot;linkQualifier&quot;, \
Link.DEFAULT_LINK_QUALIFIER))))); </ins><span class="cx"> 
</span><span class="cx">         assertTrue(getPolicy(Situation.FOUND).getCondition()
</span><del>-                .evaluate(json(object()), Link.DEFAULT_LINK_QUALIFIER));
</del><ins>+                .evaluate(json(object(field(&quot;linkQualifier&quot;, \
Link.DEFAULT_LINK_QUALIFIER))))); </ins><span class="cx"> 
</span><span class="cx">         \
assertEquals((policies.get(Situation.ABSENT.toString())).size(), 2); </span><span \
class="cx">         assertTrue(getPolicy(Situation.ABSENT).getCondition() \
</span><del>-                .evaluate(json(object()), &quot;user&quot;)); \
</del><ins>+                .evaluate(json(object(field(&quot;linkQualifier&quot;, \
&quot;user&quot;))))); </ins><span class="cx"> 
</span><span class="cx">         \
assertTrue(getPolicy(Situation.AMBIGUOUS).getCondition() </span><del>-                \
.evaluate(json(object()), Link.DEFAULT_LINK_QUALIFIER)); </del><ins>+                \
.evaluate(json(object(field(&quot;linkQualifier&quot;, \
Link.DEFAULT_LINK_QUALIFIER))))); </ins><span class="cx"> 
</span><span class="cx">         \
assertTrue(getPolicy(Situation.MISSING).getCondition() </span><del>-                \
.evaluate(json(object()), Link.DEFAULT_LINK_QUALIFIER)); </del><ins>+                \
.evaluate(json(object(field(&quot;linkQualifier&quot;, \
Link.DEFAULT_LINK_QUALIFIER))))); </ins><span class="cx"> 
</span><span class="cx">         \
assertTrue(getPolicy(Situation.SOURCE_MISSING).getCondition() </span><del>-           \
.evaluate(json(object()), Link.DEFAULT_LINK_QUALIFIER)); </del><ins>+                \
.evaluate(json(object(field(&quot;linkQualifier&quot;, \
Link.DEFAULT_LINK_QUALIFIER))))); </ins><span class="cx"> 
</span><span class="cx">         \
assertTrue(getPolicy(Situation.UNQUALIFIED).getCondition() </span><del>-              \
.evaluate(json(object()), Link.DEFAULT_LINK_QUALIFIER)); </del><ins>+                \
.evaluate(json(object(field(&quot;linkQualifier&quot;, \
Link.DEFAULT_LINK_QUALIFIER))))); </ins><span class="cx"> 
</span><span class="cx">         \
assertTrue(getPolicy(Situation.UNASSIGNED).getCondition() </span><del>-               \
.evaluate(json(object()), Link.DEFAULT_LINK_QUALIFIER)); </del><ins>+                \
.evaluate(json(object(field(&quot;linkQualifier&quot;, \
Link.DEFAULT_LINK_QUALIFIER))))); </ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     @Test
</span></span></pre></div>
<a id="trunkopenidmcoresrctestresourcesconfsyncjson"></a>
<div class="modfile"><h4>Modified: \
trunk/openidm-core/src/test/resources/conf/sync.json (5037 => 5038)</h4> <pre \
class="diff"><span> <span class="info">--- \
trunk/openidm-core/src/test/resources/conf/sync.json	2015-03-23 17:51:23 UTC (rev \
                5037)
+++ trunk/openidm-core/src/test/resources/conf/sync.json	2015-03-23 19:18:58 UTC (rev \
5038) </span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx">                 },
</span><span class="cx">                 {
</span><span class="cx">                     &quot;condition&quot; : {
</span><del>-                        &quot;linkQualifier&quot;: &quot;user&quot;
</del><ins>+                        &quot;filter&quot;: &quot;/linkQualifier eq \
\&quot;user\&quot;&quot; </ins><span class="cx">                     },
</span><span class="cx">                     &quot;situation&quot; : \
&quot;ABSENT&quot;, </span><span class="cx">                     &quot;action&quot; : \
&quot;IGNORE&quot;, </span><span class="lines">@@ -44,7 +44,7 @@
</span><span class="cx">                 },
</span><span class="cx">                 {
</span><span class="cx">                     &quot;condition&quot; : {
</span><del>-                        &quot;linkQualifier&quot;: &quot;test&quot;
</del><ins>+                        &quot;filter&quot; : &quot;/linkQualifier eq \
\&quot;test\&quot;&quot; </ins><span class="cx">                     },
</span><span class="cx">                     &quot;situation&quot; : \
&quot;ABSENT&quot;, </span><span class="cx">                     &quot;action&quot; : \
&quot;CREATE&quot;, </span></span></pre></div>
<a id="trunkopenidmzipsrcmainresourcesbindefaultsscriptrolesdefaultMappingjs"></a>
<div class="modfile"><h4>Modified: \
trunk/openidm-zip/src/main/resources/bin/defaults/script/roles/defaultMapping.js \
(5037 => 5038)</h4> <pre class="diff"><span>
<span class="info">--- \
trunk/openidm-zip/src/main/resources/bin/defaults/script/roles/defaultMapping.js	2015-03-23 \
                17:51:23 UTC (rev 5037)
+++ trunk/openidm-zip/src/main/resources/bin/defaults/script/roles/defaultMapping.js	2015-03-23 \
19:18:58 UTC (rev 5038) </span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> /** 
</span><span class="cx">  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
</span><span class="cx">  *
</span><del>- * Copyright (c) 2014 ForgeRock AS. All rights reserved.
</del><ins>+ * Copyright (c) 2014-2015 ForgeRock AS. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * The contents of this file are subject to the terms
</span><span class="cx">  * of the Common Development and Distribution License
</span><span class="lines">@@ -99,6 +99,7 @@
</span><span class="cx">     scope.sourceObject = source;
</span><span class="cx">     scope.targetObject = target;
</span><span class="cx">     scope.existingTargetObject = existingTarget;
</span><ins>+    scope.linkQualifier = linkQualifier;
</ins><span class="cx">     for (var key in config) {
</span><span class="cx">         scope[key] = config[key];
</span><span class="cx">     }
</span><span class="lines">@@ -199,36 +200,42 @@
</span><span class="cx">                 var assignment = effectiveAssignments[key];
</span><span class="cx">                 var attributes = assignment.attributes;
</span><span class="cx">                 var onAssignment = assignment.onAssignment;
</span><del>-                // Check if an onAssignment script is configured
-                if (typeof onAssignment !== 'undefined' &amp;&amp; onAssignment !== \
                null) {
-                    onAssignment.attributes = attributes;
-                    execOnScript(onAssignment);
-                }
</del><span class="cx"> 
</span><del>-                // Used to carry information across different \
                assignmentOperations
-                var attributesInfo = {};
-                // Loop through attributes, performing the assignementOperations
-                for (var i = 0; i &lt; attributes.length; i++) {
-                    var attribute = attributes[i];
-                    var assignmentOperation = attribute.assignmentOperation;
-                    var value = attribute.value;
-                    var name = attribute.name;
-                    if (assignmentOperation == null) {
-                        // Default to replace and use the entire value
-                        assignmentOperation = defaultAssignmentOperation;
</del><ins>+                // Only map if no linkQualifier was specified or the \
linkQualifier matches the assignment +                if (typeof linkQualifier === \
'undefined' || linkQualifier === null +                        || \
assignment.linkQualifiers.indexOf(linkQualifier) &gt; -1) { +
+                    // Check if an onAssignment script is configured
+                    if (typeof onAssignment !== 'undefined' &amp;&amp; onAssignment \
!== null) { +                        onAssignment.attributes = attributes;
+                        execOnScript(onAssignment);
</ins><span class="cx">                     }
</span><del>-                    // Process the assignmentOperation
-                    var config = getConfig(assignmentOperation);
-                    config.attributeName = name;
-                    config.attributeValue = value;
-                    config.attributesInfo = attributesInfo;
-                    // The result of this call should be an object with a field \
                &quot;value&quot; contianing the updated target field's value
-                    var assignmentResult = openidm.action(&quot;script&quot;, \
                &quot;eval&quot;, config, {});
-                    // Set the new target field's value
-                    target[name] = assignmentResult.value;
-                    // Update any passed back attributesInfo
-                    if (assignmentResult.hasOwnProperty(&quot;attributesInfo&quot;)) \
                {
-                        attributesInfo = assignmentResult.attributesInfo;
</del><ins>+
+                    // Used to carry information across different \
assignmentOperations +                    var attributesInfo = {};
+                    // Loop through attributes, performing the assignmentOperations
+                    for (var i = 0; i &lt; attributes.length; i++) {
+                        var attribute = attributes[i];
+                        var assignmentOperation = attribute.assignmentOperation;
+                        var value = attribute.value;
+                        var name = attribute.name;
+                        if (assignmentOperation == null) {
+                            // Default to replace and use the entire value
+                            assignmentOperation = defaultAssignmentOperation;
+                        }
+                        // Process the assignmentOperation
+                        var config = getConfig(assignmentOperation);
+                        config.attributeName = name;
+                        config.attributeValue = value;
+                        config.attributesInfo = attributesInfo;
+                        // The result of this call should be an object with a field \
&quot;value&quot; containing the updated target field's value +                       \
var assignmentResult = openidm.action(&quot;script&quot;, &quot;eval&quot;, config, \
{}); +                        // Set the new target field's value
+                        target[name] = assignmentResult.value;
+                        // Update any passed back attributesInfo
+                        if \
(assignmentResult.hasOwnProperty(&quot;attributesInfo&quot;)) { +                     \
attributesInfo = assignmentResult.attributesInfo; +                        }
</ins><span class="cx">                     }
</span><span class="cx">                 }
</span><span class="cx">             }
</span></span></pre>
</div>
</div>
<div id="footer">Copyright (c) by ForgeRock. All rights reserved.</div>

</body>
</html>



_______________________________________________
CommitOpenIDM mailing list
CommitOpenIDM@forgerock.org
https://lists.forgerock.org/mailman/listinfo/commitopenidm


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic