You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2017/11/21 10:59:01 UTC

syncope git commit: JEXL: various enhancements and cleanup, especially for templates

Repository: syncope
Updated Branches:
  refs/heads/2_0_X ff7e5af0f -> 48ae5566d


JEXL: various enhancements and cleanup, especially for templates


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/48ae5566
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/48ae5566
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/48ae5566

Branch: refs/heads/2_0_X
Commit: 48ae5566d10cc5678a0de6606c4693aeb7f32359
Parents: ff7e5af
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Tue Nov 21 11:58:53 2017 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Tue Nov 21 11:58:53 2017 +0100

----------------------------------------------------------------------
 .../java/data/JEXLItemTransformerImpl.java      |  11 +-
 .../core/provisioning/java/jexl/JexlUtils.java  | 147 +++++++++----------
 .../provisioning/java/utils/MappingUtils.java   |   6 +-
 .../provisioning/java/utils/TemplateUtils.java  |  36 ++++-
 4 files changed, 109 insertions(+), 91 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/48ae5566/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLItemTransformerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLItemTransformerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLItemTransformerImpl.java
index ae31618..01f1b7e 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLItemTransformerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLItemTransformerImpl.java
@@ -25,6 +25,7 @@ import org.apache.commons.jexl3.MapContext;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
@@ -87,10 +88,16 @@ public class JEXLItemTransformerImpl extends DefaultItemTransformer implements J
                 JexlContext jexlContext = new MapContext();
                 jexlContext.set("value", value);
                 if (entityTO instanceof AnyTO) {
-                    newValues.add(JexlUtils.evaluate(pullJEXL, (AnyTO) entityTO, jexlContext));
-                } else {
+                    JexlUtils.addFieldsToContext((AnyTO) entityTO, jexlContext);
+                    JexlUtils.addAttrTOsToContext(((AnyTO) entityTO).getPlainAttrs(), jexlContext);
+                    JexlUtils.addAttrTOsToContext(((AnyTO) entityTO).getDerAttrs(), jexlContext);
+                    JexlUtils.addAttrTOsToContext(((AnyTO) entityTO).getVirAttrs(), jexlContext);
+                } else if (entityTO instanceof RealmTO) {
+                    JexlUtils.addFieldsToContext((RealmTO) entityTO, jexlContext);
                     newValues.add(JexlUtils.evaluate(pullJEXL, jexlContext));
                 }
+
+                newValues.add(JexlUtils.evaluate(pullJEXL, jexlContext));
             }
 
             return newValues;

http://git-wip-us.apache.org/repos/asf/syncope/blob/48ae5566/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/jexl/JexlUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/jexl/JexlUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/jexl/JexlUtils.java
index f68ec60..ddb393f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/jexl/JexlUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/jexl/JexlUtils.java
@@ -25,8 +25,11 @@ import java.lang.reflect.Field;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import org.apache.commons.jexl3.JexlBuilder;
 import org.apache.commons.jexl3.JexlContext;
 import org.apache.commons.jexl3.JexlEngine;
@@ -38,6 +41,7 @@ import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.provisioning.api.utils.FormatUtils;
 import org.apache.syncope.core.persistence.api.entity.Any;
@@ -57,6 +61,10 @@ public final class JexlUtils {
 
     private static final String[] IGNORE_FIELDS = { "password", "clearPassword", "serialVersionUID", "class" };
 
+    private static final Map<Class<?>, Set<PropertyDescriptor>> FIELD_CACHE =
+            Collections.<Class<?>, Set<PropertyDescriptor>>synchronizedMap(
+                    new HashMap<Class<?>, Set<PropertyDescriptor>>());
+
     private static JexlEngine JEXL_ENGINE;
 
     private static JexlEngine getEngine() {
@@ -113,56 +121,77 @@ public final class JexlUtils {
         return result;
     }
 
-    public static JexlContext addFieldsToContext(final Object object, final JexlContext jexlContext) {
-        JexlContext context = jexlContext == null ? new MapContext() : jexlContext;
+    public static void addFieldsToContext(final Object object, final JexlContext jexlContext) {
+        Set<PropertyDescriptor> cached = FIELD_CACHE.get(object.getClass());
+        if (cached == null) {
+            cached = new HashSet<>();
+            FIELD_CACHE.put(object.getClass(), cached);
 
-        try {
-            for (PropertyDescriptor desc : Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors()) {
-                Class<?> type = desc.getPropertyType();
-                String fieldName = desc.getName();
-
-                if ((!fieldName.startsWith("pc"))
-                        && (!ArrayUtils.contains(IGNORE_FIELDS, fieldName))
-                        && (!Iterable.class.isAssignableFrom(type))
-                        && (!type.isArray())) {
-
-                    try {
-                        Object fieldValue;
-                        if (desc.getReadMethod() == null) {
-                            final Field field = object.getClass().getDeclaredField(fieldName);
-                            field.setAccessible(true);
-                            fieldValue = field.get(object);
-                        } else {
-                            fieldValue = desc.getReadMethod().invoke(object);
-                        }
-
-                        context.set(fieldName, fieldValue == null
-                                ? StringUtils.EMPTY
-                                : (type.equals(Date.class)
-                                ? FormatUtils.format((Date) fieldValue, false)
-                                : fieldValue));
-
-                        LOG.debug("Add field {} with value {}", fieldName, fieldValue);
-                    } catch (Exception iae) {
-                        LOG.error("Reading '{}' value error", fieldName, iae);
+            try {
+                for (PropertyDescriptor desc : Introspector.getBeanInfo(object.getClass()).getPropertyDescriptors()) {
+                    if ((!desc.getName().startsWith("pc"))
+                            && (!ArrayUtils.contains(IGNORE_FIELDS, desc.getName()))
+                            && (!Iterable.class.isAssignableFrom(desc.getPropertyType()))
+                            && (!desc.getPropertyType().isArray())) {
+
+                        cached.add(desc);
                     }
                 }
+            } catch (IntrospectionException ie) {
+                LOG.error("Reading class attributes error", ie);
             }
-        } catch (IntrospectionException ie) {
-            LOG.error("Reading class attributes error", ie);
         }
 
-        if (object instanceof Any) {
-            Any<?> any = (Any<?>) object;
-            if (any.getRealm() != null) {
-                context.set("realm", any.getRealm().getFullPath());
+        for (PropertyDescriptor desc : cached) {
+            String fieldName = desc.getName();
+            Class<?> fieldType = desc.getPropertyType();
+
+            try {
+                Object fieldValue;
+                if (desc.getReadMethod() == null) {
+                    final Field field = object.getClass().getDeclaredField(fieldName);
+                    field.setAccessible(true);
+                    fieldValue = field.get(object);
+                } else {
+                    fieldValue = desc.getReadMethod().invoke(object);
+                }
+                fieldValue = fieldValue == null
+                        ? StringUtils.EMPTY
+                        : (fieldType.equals(Date.class)
+                        ? FormatUtils.format((Date) fieldValue, false)
+                        : fieldValue);
+
+                jexlContext.set(fieldName, fieldValue);
+
+                LOG.debug("Add field {} with value {}", fieldName, fieldValue);
+            } catch (Exception iae) {
+                LOG.error("Reading '{}' value error", fieldName, iae);
             }
+        }
+
+        if (object instanceof Any && ((Any<?>) object).getRealm() != null) {
+            jexlContext.set("realm", ((Any<?>) object).getRealm().getFullPath());
+        } else if (object instanceof AnyTO && ((AnyTO) object).getRealm() != null) {
+            jexlContext.set("realm", ((AnyTO) object).getRealm());
         } else if (object instanceof Realm) {
-            Realm realm = (Realm) object;
-            context.set("fullPath", realm.getFullPath());
+            jexlContext.set("fullPath", ((Realm) object).getFullPath());
+        } else if (object instanceof RealmTO) {
+            jexlContext.set("fullPath", ((RealmTO) object).getFullPath());
         }
+    }
+
+    public static void addAttrTOsToContext(final Collection<AttrTO> attrs, final JexlContext jexlContext) {
+        for (AttrTO attr : attrs) {
+            if (attr.getSchema() != null) {
+                String expressionValue = attr.getValues().isEmpty()
+                        ? StringUtils.EMPTY
+                        : attr.getValues().get(0);
 
-        return context;
+                LOG.debug("Add attribute {} with value {}", attr.getSchema(), expressionValue);
+
+                jexlContext.set(attr.getSchema(), expressionValue);
+            }
+        }
     }
 
     public static void addPlainAttrsToContext(
@@ -199,44 +228,6 @@ public final class JexlUtils {
         return Boolean.parseBoolean(evaluate(mandatoryCondition, jexlContext));
     }
 
-    public static String evaluate(final String expression, final AnyTO anyTO, final JexlContext context) {
-        addFieldsToContext(anyTO, context);
-
-        for (AttrTO plainAttr : anyTO.getPlainAttrs()) {
-            List<String> values = plainAttr.getValues();
-            String expressionValue = values.isEmpty()
-                    ? StringUtils.EMPTY
-                    : values.get(0);
-
-            LOG.debug("Add plain attribute {} with value {}", plainAttr.getSchema(), expressionValue);
-
-            context.set(plainAttr.getSchema(), expressionValue);
-        }
-        for (AttrTO derAttr : anyTO.getDerAttrs()) {
-            List<String> values = derAttr.getValues();
-            String expressionValue = values.isEmpty()
-                    ? StringUtils.EMPTY
-                    : values.get(0);
-
-            LOG.debug("Add derived attribute {} with value {}", derAttr.getSchema(), expressionValue);
-
-            context.set(derAttr.getSchema(), expressionValue);
-        }
-        for (AttrTO virAttr : anyTO.getVirAttrs()) {
-            List<String> values = virAttr.getValues();
-            String expressionValue = values.isEmpty()
-                    ? StringUtils.EMPTY
-                    : values.get(0);
-
-            LOG.debug("Add virtual attribute {} with value {}", virAttr.getSchema(), expressionValue);
-
-            context.set(virAttr.getSchema(), expressionValue);
-        }
-
-        // Evaluate expression using the context prepared before
-        return evaluate(expression, context);
-    }
-
     /**
      * Private default constructor, for static-only classes.
      */

http://git-wip-us.apache.org/repos/asf/syncope/blob/48ae5566/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
index ba2c7a4..67f2fe0 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/MappingUtils.java
@@ -87,7 +87,7 @@ public final class MappingUtils {
         });
     }
 
-    private static Name evaluateNAME(final String evalConnObjectLink, final String connObjectKey) {
+    private static Name getName(final String evalConnObjectLink, final String connObjectKey) {
         // If connObjectLink evaluates to an empty string, just use the provided connObjectKey as Name(),
         // otherwise evaluated connObjectLink expression is taken as Name().
         Name name;
@@ -135,7 +135,7 @@ public final class MappingUtils {
             evalConnObjectLink = JexlUtils.evaluate(connObjectLink, jexlContext);
         }
 
-        return evaluateNAME(evalConnObjectLink, connObjectKey);
+        return getName(evalConnObjectLink, connObjectKey);
     }
 
     /**
@@ -165,7 +165,7 @@ public final class MappingUtils {
             evalConnObjectLink = JexlUtils.evaluate(connObjectLink, jexlContext);
         }
 
-        return evaluateNAME(evalConnObjectLink, connObjectKey);
+        return getName(evalConnObjectLink, connObjectKey);
     }
 
     private static List<ItemTransformer> getItemTransformers(

http://git-wip-us.apache.org/repos/asf/syncope/blob/48ae5566/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/TemplateUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/TemplateUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/TemplateUtils.java
index 2b342af..5df7cce 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/TemplateUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/TemplateUtils.java
@@ -51,13 +51,13 @@ public class TemplateUtils {
     @Autowired
     private GroupDAO groupDAO;
 
-    private AttrTO evaluateAttr(final AnyTO anyTO, final AttrTO template) {
+    private AttrTO evaluateAttr(final AttrTO template, final MapContext jexlContext) {
         AttrTO result = new AttrTO();
         result.setSchema(template.getSchema());
 
         if (template.getValues() != null && !template.getValues().isEmpty()) {
             for (String value : template.getValues()) {
-                String evaluated = JexlUtils.evaluate(value, anyTO, new MapContext());
+                String evaluated = JexlUtils.evaluate(value, jexlContext);
                 if (StringUtils.isNotBlank(evaluated)) {
                     result.getValues().add(evaluated);
                 }
@@ -68,8 +68,14 @@ public class TemplateUtils {
     }
 
     private void fill(final AnyTO anyTO, final AnyTO template) {
+        MapContext jexlContext = new MapContext();
+        JexlUtils.addFieldsToContext(anyTO, jexlContext);
+        JexlUtils.addAttrTOsToContext(anyTO.getPlainAttrs(), jexlContext);
+        JexlUtils.addAttrTOsToContext(anyTO.getDerAttrs(), jexlContext);
+        JexlUtils.addAttrTOsToContext(anyTO.getVirAttrs(), jexlContext);
+
         if (template.getRealm() != null) {
-            String evaluated = JexlUtils.evaluate(template.getRealm(), anyTO, new MapContext());
+            String evaluated = JexlUtils.evaluate(template.getRealm(), jexlContext);
             if (StringUtils.isNotBlank(evaluated)) {
                 anyTO.setRealm(evaluated);
             }
@@ -81,7 +87,11 @@ public class TemplateUtils {
                     && (!currentAttrMap.containsKey(templatePlainAttr.getSchema())
                     || currentAttrMap.get(templatePlainAttr.getSchema()).getValues().isEmpty())) {
 
-                anyTO.getPlainAttrs().add(evaluateAttr(anyTO, templatePlainAttr));
+                AttrTO evaluated = evaluateAttr(templatePlainAttr, jexlContext);
+                if (!evaluated.getValues().isEmpty()) {
+                    anyTO.getPlainAttrs().add(evaluated);
+                    jexlContext.set(evaluated.getSchema(), evaluated.getValues().get(0));
+                }
             }
         }
 
@@ -98,7 +108,11 @@ public class TemplateUtils {
                     && (!currentAttrMap.containsKey(templateVirAttr.getSchema())
                     || currentAttrMap.get(templateVirAttr.getSchema()).getValues().isEmpty())) {
 
-                anyTO.getVirAttrs().add(evaluateAttr(anyTO, templateVirAttr));
+                AttrTO evaluated = evaluateAttr(templateVirAttr, jexlContext);
+                if (!evaluated.getValues().isEmpty()) {
+                    anyTO.getVirAttrs().add(evaluated);
+                    jexlContext.set(evaluated.getSchema(), evaluated.getValues().get(0));
+                }
             }
         }
 
@@ -134,19 +148,25 @@ public class TemplateUtils {
     public <T extends AnyTO> void apply(final T anyTO, final AnyTO template) {
         fill(anyTO, template);
 
+        MapContext jexlContext = new MapContext();
+        JexlUtils.addFieldsToContext(anyTO, jexlContext);
+        JexlUtils.addAttrTOsToContext(anyTO.getPlainAttrs(), jexlContext);
+        JexlUtils.addAttrTOsToContext(anyTO.getDerAttrs(), jexlContext);
+        JexlUtils.addAttrTOsToContext(anyTO.getVirAttrs(), jexlContext);
+
         if (template instanceof AnyObjectTO) {
             fillRelationships((GroupableRelatableTO) anyTO, ((GroupableRelatableTO) template));
             fillMemberships((GroupableRelatableTO) anyTO, ((GroupableRelatableTO) template));
         } else if (template instanceof UserTO) {
             if (StringUtils.isNotBlank(((UserTO) template).getUsername())) {
-                String evaluated = JexlUtils.evaluate(((UserTO) template).getUsername(), anyTO, new MapContext());
+                String evaluated = JexlUtils.evaluate(((UserTO) template).getUsername(), jexlContext);
                 if (StringUtils.isNotBlank(evaluated)) {
                     ((UserTO) anyTO).setUsername(evaluated);
                 }
             }
 
             if (StringUtils.isNotBlank(((UserTO) template).getPassword())) {
-                String evaluated = JexlUtils.evaluate(((UserTO) template).getPassword(), anyTO, new MapContext());
+                String evaluated = JexlUtils.evaluate(((UserTO) template).getPassword(), jexlContext);
                 if (StringUtils.isNotBlank(evaluated)) {
                     ((UserTO) anyTO).setPassword(evaluated);
                 }
@@ -156,7 +176,7 @@ public class TemplateUtils {
             fillMemberships((GroupableRelatableTO) anyTO, ((GroupableRelatableTO) template));
         } else if (template instanceof GroupTO) {
             if (StringUtils.isNotBlank(((GroupTO) template).getName())) {
-                String evaluated = JexlUtils.evaluate(((GroupTO) template).getName(), anyTO, new MapContext());
+                String evaluated = JexlUtils.evaluate(((GroupTO) template).getName(), jexlContext);
                 if (StringUtils.isNotBlank(evaluated)) {
                     ((GroupTO) anyTO).setName(evaluated);
                 }