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 2016/05/16 12:49:28 UTC

[1/2] syncope git commit: [SYNCOPE-857] Feature provided

Repository: syncope
Updated Branches:
  refs/heads/master ecc062ca5 -> 5ee30a666


http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index b890f50..c742c1a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -58,6 +58,7 @@ import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
 import org.apache.syncope.core.spring.security.PasswordGenerator;
 import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
+import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -74,6 +75,7 @@ import org.apache.syncope.core.provisioning.api.DerAttrHandler;
 import org.apache.syncope.core.provisioning.api.MappingManager;
 import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
+import org.apache.syncope.core.provisioning.java.data.JEXLMappingItemTransformer;
 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
 import org.identityconnectors.framework.common.FrameworkUtil;
 import org.identityconnectors.framework.common.objects.Attribute;
@@ -114,6 +116,9 @@ public class MappingManagerImpl implements MappingManager {
     private UserDAO userDAO;
 
     @Autowired
+    private AnyObjectDAO anyObjectDAO;
+
+    @Autowired
     private DerAttrHandler derAttrHandler;
 
     @Autowired
@@ -254,12 +259,31 @@ public class MappingManagerImpl implements MappingManager {
     public static List<MappingItemTransformer> getMappingItemTransformers(final MappingItem mappingItem) {
         List<MappingItemTransformer> result = new ArrayList<>();
 
+        // First consider the JEXL transformation expressions
+        JEXLMappingItemTransformer jexlTransformer = null;
+        if (StringUtils.isNotBlank(mappingItem.getPropagationJEXLTransformer())
+                || StringUtils.isNotBlank(mappingItem.getPullJEXLTransformer())) {
+
+            try {
+                jexlTransformer = (JEXLMappingItemTransformer) ApplicationContextProvider.getBeanFactory().
+                        createBean(JEXLMappingItemTransformer.class, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false);
+
+                jexlTransformer.setPropagationJEXL(mappingItem.getPropagationJEXLTransformer());
+                jexlTransformer.setPullJEXL(mappingItem.getPullJEXLTransformer());
+            } catch (Exception e) {
+                LOG.error("Could not instantiate {}, ignoring...", JEXLMappingItemTransformer.class.getName(), e);
+            }
+        }
+        if (jexlTransformer != null) {
+            result.add(jexlTransformer);
+        }
+
+        // Then other custom tranaformers
         for (String className : mappingItem.getMappingItemTransformerClassNames()) {
             try {
                 Class<?> transformerClass = ClassUtils.getClass(className);
 
-                result.add((MappingItemTransformer) ApplicationContextProvider.
-                        getBeanFactory().
+                result.add((MappingItemTransformer) ApplicationContextProvider.getBeanFactory().
                         createBean(transformerClass, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false));
             } catch (Exception e) {
                 LOG.error("Could not instantiate {}, ignoring...", className, e);
@@ -395,9 +419,9 @@ public class MappingManagerImpl implements MappingManager {
 
             case GROUP:
                 if (any instanceof User) {
-                    for (Group group : userDAO.findAllGroups((User) any)) {
-                        anys.add(group);
-                    }
+                    anys.addAll(userDAO.findAllGroups((User) any));
+                } else if (any instanceof AnyObject) {
+                    anys.addAll(anyObjectDAO.findAllGroups((AnyObject) any));
                 } else if (any instanceof Group) {
                     anys.add(any);
                 }
@@ -525,8 +549,8 @@ public class MappingManagerImpl implements MappingManager {
      */
     @Transactional(readOnly = true)
     @Override
-    public List<PlainAttrValue> getIntValues(final Provision provision,
-            final MappingItem mappingItem, final List<Any<?>> anys) {
+    public List<PlainAttrValue> getIntValues(
+            final Provision provision, final MappingItem mappingItem, final List<Any<?>> anys) {
 
         LOG.debug("Get attributes for '{}' and mapping type '{}'", anys, mappingItem.getIntMappingType());
 
@@ -682,7 +706,7 @@ public class MappingManagerImpl implements MappingManager {
         List<PlainAttrValue> transformed = values;
         if (transform) {
             for (MappingItemTransformer transformer : getMappingItemTransformers(mappingItem)) {
-                transformed = transformer.beforePropagation(transformed);
+                transformed = transformer.beforePropagation(mappingItem, anys, transformed);
             }
             LOG.debug("Transformed values for propagation: {}", values);
         } else {
@@ -713,7 +737,6 @@ public class MappingManagerImpl implements MappingManager {
      * Set attribute values, according to the given {@link MappingItem}, to any object from attribute received from
      * connector.
      *
-     * @param <T> any object
      * @param mappingItem mapping item
      * @param attr attribute received from connector
      * @param anyTO any object
@@ -721,14 +744,14 @@ public class MappingManagerImpl implements MappingManager {
      */
     @Transactional(readOnly = true)
     @Override
-    public <T extends AnyTO> void setIntValues(
-            final MappingItem mappingItem, final Attribute attr, final T anyTO, final AnyUtils anyUtils) {
+    public void setIntValues(
+            final MappingItem mappingItem, final Attribute attr, final AnyTO anyTO, final AnyUtils anyUtils) {
 
         List<Object> values = null;
         if (attr != null) {
             values = attr.getValue();
             for (MappingItemTransformer transformer : getMappingItemTransformers(mappingItem)) {
-                values = transformer.beforePull(values);
+                values = transformer.beforePull(mappingItem, anyTO, values);
             }
         }
         values = ListUtils.emptyIfNull(values);

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
index 70cd1d0..7ed913d 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/DefaultMappingItemTransformer.java
@@ -19,21 +19,35 @@
 package org.apache.syncope.core.provisioning.java.data;
 
 import java.util.List;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
+import org.springframework.transaction.annotation.Transactional;
 
 /**
  * Default (empty) implementation of {@link MappingItemTransformer}.
  */
 public class DefaultMappingItemTransformer implements MappingItemTransformer {
 
+    @Transactional(readOnly = true)
     @Override
-    public List<PlainAttrValue> beforePropagation(final List<PlainAttrValue> values) {
+    public List<PlainAttrValue> beforePropagation(
+            final MappingItem mappingItem,
+            final List<Any<?>> anys,
+            final List<PlainAttrValue> values) {
+
         return values;
     }
 
+    @Transactional(readOnly = true)
     @Override
-    public List<Object> beforePull(final List<Object> values) {
+    public List<Object> beforePull(
+            final MappingItem mappingItem,
+            final AnyTO anyTO,
+            final List<Object> values) {
+
         return values;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLMappingItemTransformer.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLMappingItemTransformer.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLMappingItemTransformer.java
new file mode 100644
index 0000000..e4e155a
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/JEXLMappingItemTransformer.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.core.provisioning.java.data;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.jexl3.JexlContext;
+import org.apache.commons.jexl3.MapContext;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
+
+/**
+ * {@link org.apache.syncope.core.provisioning.api.data.MappingItemTransformer} implemeting evaluation of JEXL
+ * expression defined for a given {@link MappingItem}.
+ */
+public class JEXLMappingItemTransformer extends DefaultMappingItemTransformer {
+
+    private String propagationJEXL;
+
+    private String pullJEXL;
+
+    public void setPropagationJEXL(final String propagationJEXL) {
+        this.propagationJEXL = propagationJEXL;
+    }
+
+    public void setPullJEXL(final String pullJEXL) {
+        this.pullJEXL = pullJEXL;
+    }
+
+    @Override
+    public List<PlainAttrValue> beforePropagation(
+            final MappingItem mappingItem,
+            final List<Any<?>> anys,
+            final List<PlainAttrValue> values) {
+
+        if (StringUtils.isNotBlank(propagationJEXL) && values != null) {
+            Any<?> any = null;
+            if (!anys.isEmpty()) {
+                switch (mappingItem.getMapping().getProvision().getAnyType().getKind()) {
+                    case USER:
+                        any = IterableUtils.find(anys, new Predicate<Any<?>>() {
+
+                            @Override
+                            public boolean evaluate(final Any<?> object) {
+                                return object instanceof User;
+                            }
+                        });
+                        break;
+
+                    case GROUP:
+                        any = IterableUtils.find(anys, new Predicate<Any<?>>() {
+
+                            @Override
+                            public boolean evaluate(final Any<?> object) {
+                                return object instanceof Group;
+                            }
+                        });
+                        break;
+
+                    case ANY_OBJECT:
+                        any = IterableUtils.find(anys, new Predicate<Any<?>>() {
+
+                            @Override
+                            public boolean evaluate(final Any<?> object) {
+                                return object instanceof AnyObject;
+                            }
+                        });
+                        break;
+
+                    default:
+                }
+            }
+
+            for (PlainAttrValue value : values) {
+                JexlContext jexlContext = new MapContext();
+                if (any != null) {
+                    JexlUtils.addFieldsToContext(any, jexlContext);
+                    JexlUtils.addPlainAttrsToContext(any.getPlainAttrs(), jexlContext);
+                    JexlUtils.addDerAttrsToContext(any, jexlContext);
+                }
+                jexlContext.set("value", value.getValueAsString());
+
+                value.setStringValue(JexlUtils.evaluate(propagationJEXL, jexlContext));
+            }
+
+            return values;
+        }
+
+        return super.beforePropagation(mappingItem, anys, values);
+    }
+
+    @Override
+    public List<Object> beforePull(
+            final MappingItem mappingItem,
+            final AnyTO anyTO,
+            final List<Object> values) {
+
+        if (StringUtils.isNotBlank(pullJEXL) && values != null) {
+
+            List<Object> newValues = new ArrayList<>(values.size());
+            for (Object value : values) {
+                JexlContext jexlContext = new MapContext();
+                jexlContext.set("value", value);
+                if (anyTO == null) {
+                    newValues.add(JexlUtils.evaluate(pullJEXL, jexlContext));
+                } else {
+                    newValues.add(JexlUtils.evaluate(pullJEXL, anyTO, jexlContext));
+                }
+            }
+
+            return newValues;
+        }
+
+        return super.beforePull(mappingItem, anyTO, values);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/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 7c6c38a..af3aa52 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
@@ -193,9 +193,7 @@ public final class JexlUtils {
         return Boolean.parseBoolean(evaluate(mandatoryCondition, jexlContext));
     }
 
-    public static String evaluate(final String expression, final AnyTO anyTO) {
-        final JexlContext context = new MapContext();
-
+    public static String evaluate(final String expression, final AnyTO anyTO, final JexlContext context) {
         addFieldsToContext(anyTO, context);
 
         for (AttrTO plainAttr : anyTO.getPlainAttrs()) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
index d752cd5..990127a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PlainAttrsPullCorrelationRule.java
@@ -55,19 +55,18 @@ public class PlainAttrsPullCorrelationRule implements PullCorrelationRule {
         SearchCond searchCond = null;
 
         for (String schema : plainSchemaNames) {
-            Attribute attr = mappingItems.get(schema) == null
+            MappingItem mappingItem = mappingItems.get(schema);
+            Attribute attr = mappingItem == null
                     ? null
-                    : connObj.getAttributeByName(mappingItems.get(schema).getExtAttrName());
+                    : connObj.getAttributeByName(mappingItem.getExtAttrName());
             if (attr == null) {
                 throw new IllegalArgumentException(
                         "Connector object does not contains the attributes to perform the search: " + schema);
             }
 
             List<Object> values = attr.getValue();
-            for (MappingItemTransformer transformer
-                    : MappingManagerImpl.getMappingItemTransformers(mappingItems.get(schema))) {
-
-                values = transformer.beforePull(values);
+            for (MappingItemTransformer transformer : MappingManagerImpl.getMappingItemTransformers(mappingItem)) {
+                values = transformer.beforePull(mappingItem, null, values);
             }
 
             AttributeCond.Type type;

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
index 59292b3..599aabf 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
@@ -171,7 +171,10 @@ public class PullUtils {
 
         String transfUid = uid;
         for (MappingItemTransformer transformer : MappingManagerImpl.getMappingItemTransformers(connObjectKeyItem)) {
-            List<Object> output = transformer.beforePull(Collections.<Object>singletonList(transfUid));
+            List<Object> output = transformer.beforePull(
+                    connObjectKeyItem,
+                    null,
+                    Collections.<Object>singletonList(transfUid));
             if (output != null && !output.isEmpty()) {
                 transfUid = output.get(0).toString();
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/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 1c51d6d..f750cbf 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
@@ -20,6 +20,7 @@ package org.apache.syncope.core.provisioning.java.utils;
 
 import java.util.List;
 import java.util.Map;
+import org.apache.commons.jexl3.MapContext;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.SyncopeClientException;
@@ -56,7 +57,7 @@ public class TemplateUtils {
 
         if (template.getValues() != null && !template.getValues().isEmpty()) {
             for (String value : template.getValues()) {
-                String evaluated = JexlUtils.evaluate(value, anyTO);
+                String evaluated = JexlUtils.evaluate(value, anyTO, new MapContext());
                 if (StringUtils.isNotBlank(evaluated)) {
                     result.getValues().add(evaluated);
                 }
@@ -138,14 +139,14 @@ public class TemplateUtils {
                         ((AnyObjectTO) anyTO).getMemberships(), ((AnyObjectTO) template).getMemberships());
             } else if (template instanceof UserTO) {
                 if (StringUtils.isNotBlank(((UserTO) template).getUsername())) {
-                    String evaluated = JexlUtils.evaluate(((UserTO) template).getUsername(), anyTO);
+                    String evaluated = JexlUtils.evaluate(((UserTO) template).getUsername(), anyTO, new MapContext());
                     if (StringUtils.isNotBlank(evaluated)) {
                         ((UserTO) anyTO).setUsername(evaluated);
                     }
                 }
 
                 if (StringUtils.isNotBlank(((UserTO) template).getPassword())) {
-                    String evaluated = JexlUtils.evaluate(((UserTO) template).getPassword(), anyTO);
+                    String evaluated = JexlUtils.evaluate(((UserTO) template).getPassword(), anyTO, new MapContext());
                     if (StringUtils.isNotBlank(evaluated)) {
                         ((UserTO) anyTO).setPassword(evaluated);
                     }
@@ -157,7 +158,7 @@ public class TemplateUtils {
                         ((UserTO) anyTO).getMemberships(), ((UserTO) template).getMemberships());
             } else if (template instanceof GroupTO) {
                 if (StringUtils.isNotBlank(((GroupTO) template).getName())) {
-                    String evaluated = JexlUtils.evaluate(((GroupTO) template).getName(), anyTO);
+                    String evaluated = JexlUtils.evaluate(((GroupTO) template).getName(), anyTO, new MapContext());
                     if (StringUtils.isNotBlank(evaluated)) {
                         ((GroupTO) anyTO).setName(evaluated);
                     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java
index 3d79fda..7fc60df 100644
--- a/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java
+++ b/fit/core-reference/src/main/java/org/apache/syncope/fit/core/reference/PrefixMappingItemTransformer.java
@@ -21,7 +21,10 @@ package org.apache.syncope.fit.core.reference;
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.provisioning.java.data.DefaultMappingItemTransformer;
 
 public class PrefixMappingItemTransformer extends DefaultMappingItemTransformer {
@@ -29,9 +32,13 @@ public class PrefixMappingItemTransformer extends DefaultMappingItemTransformer
     public static final String PREFIX = "PREFIX_";
 
     @Override
-    public List<PlainAttrValue> beforePropagation(final List<PlainAttrValue> values) {
+    public List<PlainAttrValue> beforePropagation(
+            final MappingItem mappingItem,
+            final List<Any<?>> anys,
+            final List<PlainAttrValue> values) {
+
         if (values == null || values.isEmpty() || values.get(0).getStringValue() == null) {
-            return super.beforePropagation(values);
+            return super.beforePropagation(mappingItem, anys, values);
         } else {
             String value = values.get(0).getStringValue();
             values.get(0).setStringValue(PREFIX + value);
@@ -41,9 +48,13 @@ public class PrefixMappingItemTransformer extends DefaultMappingItemTransformer
     }
 
     @Override
-    public List<Object> beforePull(final List<Object> values) {
+    public List<Object> beforePull(
+            final MappingItem mappingItem,
+            final AnyTO anyTO,
+            final List<Object> values) {
+
         if (values == null || values.isEmpty() || values.get(0) == null) {
-            return super.beforePull(values);
+            return super.beforePull(mappingItem, anyTO, values);
         } else {
             List<Object> newValues = new ArrayList<>(values);
             newValues.set(0, StringUtils.substringAfter(values.get(0).toString(), PREFIX));

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java
index c698ea6..a36d1cc 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/TopologyITCase.java
@@ -97,12 +97,12 @@ public class TopologyITCase extends AbstractConsoleITCase {
         wicketTester.assertComponent("body:toggle:outerObjectsRepeater:3:outer:form:content:provision:"
                 + "container:content:wizard:form:view:mapping:mappingContainer:mappings:1", WebMarkupContainer.class);
 
-        wicketTester.executeAjaxEvent("body:toggle:outerObjectsRepeater:3:outer:form:content:provision:"
-                + "container:content:wizard:form:view:mapping:mappingContainer:mappings:1:transformers:icon",
+        wicketTester.executeAjaxEvent("body:toggle:outerObjectsRepeater:3:outer:form:content:provision:container:"
+                + "content:wizard:form:view:mapping:mappingContainer:mappings:1:mappingItemTransformers:icon",
                 Constants.ON_CLICK);
 
         wicketTester.clickLink("body:toggle:outerObjectsRepeater:3:outer:form:content:provision:container:content:"
-                + "wizard:form:view:mapping:mappingContainer:mappings:0:transformers:alertsLink");
+                + "wizard:form:view:mapping:mappingContainer:mappings:0:mappingItemTransformers:alertsLink");
 
         wicketTester.assertComponent("body:toggle:outerObjectsRepeater:3:outer:form:content:provision:container:"
                 + "content:wizard:outerObjectsRepeater:0:outer:container:content:togglePanelContainer:"
@@ -119,8 +119,8 @@ public class TopologyITCase extends AbstractConsoleITCase {
         wicketTester.executeAjaxEvent(
                 "body:toggle:container:content:togglePanelContainer:container:actions:create", Constants.ON_CLICK);
 
-        FormTester formTester
-                = wicketTester.newFormTester("body:toggle:outerObjectsRepeater:0:outer:form:content:form");
+        FormTester formTester =
+                wicketTester.newFormTester("body:toggle:outerObjectsRepeater:0:outer:form:content:form");
 
         formTester.setValue("view:container:key:textField", res);
         formTester.submit("buttons:next");

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
index 4008a08..762049e 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
@@ -25,11 +25,19 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
 import java.util.List;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.lang3.SerializationUtils;
 import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.PropagationTaskTO;
 import org.apache.syncope.common.lib.to.ExecTO;
+import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.ProvisionTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.TaskType;
@@ -104,6 +112,50 @@ public class PropagationTaskITCase extends AbstractTaskITCase {
     }
 
     @Test
+    public void propagationJEXLTransformer() {
+        // 0. Set propagation JEXL MappingItemTransformer
+        ResourceTO resource = resourceService.read(RESOURCE_NAME_DBSCRIPTED);
+        ResourceTO originalResource = SerializationUtils.clone(resource);
+        ProvisionTO provision = resource.getProvision("PRINTER");
+        assertNotNull(provision);
+
+        MappingItemTO mappingItem = IterableUtils.find(
+                provision.getMapping().getItems(), new Predicate<MappingItemTO>() {
+
+            @Override
+            public boolean evaluate(final MappingItemTO object) {
+                return "location".equals(object.getIntAttrName());
+            }
+        });
+        assertNotNull(mappingItem);
+        assertTrue(mappingItem.getMappingItemTransformerClassNames().isEmpty());
+
+        String suffix = getUUIDString();
+        mappingItem.setPropagationJEXLTransformer("value + '" + suffix + "'");
+
+        try {
+            resourceService.update(resource);
+
+            // 1. create printer on external resource
+            AnyObjectTO anyObjectTO = AnyObjectITCase.getSampleTO("propagationJEXLTransformer");
+            String originalLocation = anyObjectTO.getPlainAttrMap().get("location").getValues().get(0);
+            assertFalse(originalLocation.endsWith(suffix));
+
+            anyObjectTO = createAnyObject(anyObjectTO).getAny();
+            assertNotNull(anyObjectTO);
+
+            // 2. verify that JEXL MappingItemTransformer was applied during propagation
+            // (location ends with given suffix on external resource)
+            ConnObjectTO connObjectTO = resourceService.
+                    readConnObject(RESOURCE_NAME_DBSCRIPTED, anyObjectTO.getType(), anyObjectTO.getKey());
+            assertFalse(anyObjectTO.getPlainAttrMap().get("location").getValues().get(0).endsWith(suffix));
+            assertTrue(connObjectTO.getPlainAttrMap().get("LOCATION").getValues().get(0).endsWith(suffix));
+        } finally {
+            resourceService.update(originalResource);
+        }
+    }
+
+    @Test
     public void issueSYNCOPE741() {
         for (int i = 0; i < 3; i++) {
             taskService.execute(new ExecuteQuery.Builder().
@@ -142,7 +194,8 @@ public class PropagationTaskITCase extends AbstractTaskITCase {
         assertFalse(task.getExecutions().isEmpty());
 
         // check list executions
-        PagedResult<ExecTO> execs = taskService.listExecutions(new ExecQuery.Builder().key("1e697572-b896-484c-ae7f-0c8f63fcbc6c").
+        PagedResult<ExecTO> execs = taskService.listExecutions(new ExecQuery.Builder().key(
+                "1e697572-b896-484c-ae7f-0c8f63fcbc6c").
                 page(1).size(2).build());
         assertTrue(execs.getTotalCount() >= execs.getResult().size());
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
index 49e5d2e..12bf74f 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PullTaskITCase.java
@@ -396,21 +396,21 @@ public class PullTaskITCase extends AbstractTaskITCase {
         ProvisionTO provision = resource.getProvision("PRINTER");
         assertNotNull(provision);
 
-        try {
-            provision.setSyncToken(null);
+        provision.setSyncToken(null);
 
-            MappingItemTO mappingItem = IterableUtils.find(
-                    provision.getMapping().getItems(), new Predicate<MappingItemTO>() {
+        MappingItemTO mappingItem = IterableUtils.find(
+                provision.getMapping().getItems(), new Predicate<MappingItemTO>() {
 
-                @Override
-                public boolean evaluate(final MappingItemTO object) {
-                    return "location".equals(object.getIntAttrName());
-                }
-            });
-            assertNotNull(mappingItem);
-            mappingItem.getMappingItemTransformerClassNames().clear();
-            mappingItem.getMappingItemTransformerClassNames().add(PrefixMappingItemTransformer.class.getName());
+            @Override
+            public boolean evaluate(final MappingItemTO object) {
+                return "location".equals(object.getIntAttrName());
+            }
+        });
+        assertNotNull(mappingItem);
+        mappingItem.getMappingItemTransformerClassNames().clear();
+        mappingItem.getMappingItemTransformerClassNames().add(PrefixMappingItemTransformer.class.getName());
 
+        try {
             resourceService.update(resource);
 
             // 1. create printer on external resource


[2/2] syncope git commit: [SYNCOPE-857] Feature provided

Posted by il...@apache.org.
[SYNCOPE-857] Feature provided


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

Branch: refs/heads/master
Commit: 5ee30a666a67eff9192c1eed37001b0924563c19
Parents: ecc062c
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Mon May 16 14:49:16 2016 +0200
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Mon May 16 14:49:16 2016 +0200

----------------------------------------------------------------------
 .../resource/ResourceResultManager.java         |   6 +-
 .../console/tasks/PullTaskDirectoryPanel.java   |   2 +-
 .../console/tasks/SchedTaskDirectoryPanel.java  |   8 +-
 .../console/tasks/TransformersTogglePanel.java  | 122 ----------------
 .../markup/html/form/AjaxTextFieldPanel.java    |   2 +-
 .../console/widgets/JEXLTransformerWidget.java  |  95 +++++++++++++
 .../widgets/MappingItemTransformerWidget.java   |   7 +-
 .../console/wizards/any/GroupDetails.java       |   2 +-
 .../client/console/wizards/any/PlainAttrs.java  |   2 +-
 .../client/console/wizards/any/UserDetails.java |   2 +-
 .../client/console/wizards/any/VirAttrs.java    |   2 +-
 .../resources/JEXLTransformersTogglePanel.java  |  77 ++++++++++
 .../MappingItemTransformersTogglePanel.java     | 120 ++++++++++++++++
 .../resources/ProvisionWizardBuilder.java       |  14 +-
 .../wizards/resources/ResourceMappingPanel.java |  29 ++--
 .../META-INF/resources/css/syncopeConsole.css   |  23 ++-
 .../console/tasks/TransformersTogglePanel.html  |  32 -----
 .../tasks/TransformersTogglePanel.properties    |  19 ---
 .../tasks/TransformersTogglePanel_it.properties |  19 ---
 .../TransformersTogglePanel_pt_BR.properties    |  19 ---
 .../tasks/TransformersTogglePanel_ru.properties |  19 ---
 .../widgets/JEXLTransformerWidget.properties    |  18 +++
 .../widgets/JEXLTransformerWidget_it.properties |  18 +++
 .../JEXLTransformerWidget_pt_BR.properties      |  18 +++
 .../widgets/JEXLTransformerWidget_ru.properties |  21 +++
 .../MappingItemTransformerWidget.properties     |   2 +-
 .../MappingItemTransformerWidget_it.properties  |   2 +-
 ...appingItemTransformerWidget_pt_BR.properties |   4 +-
 .../MappingItemTransformerWidget_ru.properties  |   2 +-
 .../resources/JEXLTransformersTogglePanel.html  |  33 +++++
 .../MappingItemTransformersTogglePanel.html     |  32 +++++
 ...appingItemTransformersTogglePanel.properties |  19 +++
 ...ingItemTransformersTogglePanel_it.properties |  19 +++
 ...ItemTransformersTogglePanel_pt_BR.properties |  19 +++
 ...ingItemTransformersTogglePanel_ru.properties |  19 +++
 .../wizards/resources/ResourceMappingPanel.html |   8 +-
 .../syncope/common/lib/to/MappingItemTO.java    |  26 ++++
 .../init/ClassPathScanImplementationLookup.java |   5 +-
 .../api/entity/LinkingMappingItem.java          |  20 +++
 .../api/entity/resource/MappingItem.java        |   8 ++
 .../jpa/entity/resource/JPAMappingItem.java     |  32 +++++
 .../api/data/MappingItemTransformer.java        |  17 ++-
 .../provisioning/java/MappingManagerImpl.java   |  47 ++++--
 .../data/DefaultMappingItemTransformer.java     |  18 ++-
 .../java/data/JEXLMappingItemTransformer.java   | 142 +++++++++++++++++++
 .../core/provisioning/java/jexl/JexlUtils.java  |   4 +-
 .../pushpull/PlainAttrsPullCorrelationRule.java |  11 +-
 .../provisioning/java/pushpull/PullUtils.java   |   5 +-
 .../provisioning/java/utils/TemplateUtils.java  |   9 +-
 .../reference/PrefixMappingItemTransformer.java |  19 ++-
 .../syncope/fit/console/TopologyITCase.java     |  10 +-
 .../syncope/fit/core/PropagationTaskITCase.java |  55 ++++++-
 .../apache/syncope/fit/core/PullTaskITCase.java |  24 ++--
 53 files changed, 979 insertions(+), 328 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/cli/src/main/java/org/apache/syncope/client/cli/commands/resource/ResourceResultManager.java
----------------------------------------------------------------------
diff --git a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/resource/ResourceResultManager.java b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/resource/ResourceResultManager.java
index 042207a..e396316 100644
--- a/client/cli/src/main/java/org/apache/syncope/client/cli/commands/resource/ResourceResultManager.java
+++ b/client/cli/src/main/java/org/apache/syncope/client/cli/commands/resource/ResourceResultManager.java
@@ -81,7 +81,11 @@ public class ResourceResultManager extends CommonsResultManager {
             System.out.println("             internal attribute name: " + mappingItemTO.getIntAttrName());
             System.out.println("             external attribute name: " + mappingItemTO.getExtAttrName());
             System.out.println("             mandatory condition: " + mappingItemTO.getMandatoryCondition());
-            System.out.println("             transformers class: "
+            System.out.println("             JEXL propagation transformer: "
+                    + mappingItemTO.getPropagationJEXLTransformer());
+            System.out.println("             JEXL pull transformer: "
+                    + mappingItemTO.getPullJEXLTransformer());
+            System.out.println("             transformers classes: "
                     + mappingItemTO.getMappingItemTransformerClassNames());
             System.out.println("             purpose: " + mappingItemTO.getPurpose());
             System.out.println("             connector object key: " + mappingItemTO.isConnObjectKey());

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/tasks/PullTaskDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/PullTaskDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/PullTaskDirectoryPanel.java
index d6a294a..9e8c69e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/PullTaskDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/PullTaskDirectoryPanel.java
@@ -53,7 +53,7 @@ public abstract class PullTaskDirectoryPanel extends ProvisioningTaskDirectoryPa
     }
 
     @Override
-    protected void addFurtherAcions(final ActionLinksPanel.Builder<PullTaskTO> panel, final IModel<PullTaskTO> model) {
+    protected void addFurtherActions(final ActionLinksPanel.Builder<PullTaskTO> panel, final IModel<PullTaskTO> model) {
         panel.add(new ActionLink<PullTaskTO>() {
 
             private static final long serialVersionUID = -3722207913631435501L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
index 3dce121..504bb0d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
@@ -183,9 +183,7 @@ public abstract class SchedTaskDirectoryPanel<T extends SchedTaskTO>
             private static final long serialVersionUID = 2054811145491901166L;
 
             @Override
-            public ActionLinksPanel<T> getActions(
-                    final String componentId, final IModel<T> model) {
-
+            public ActionLinksPanel<T> getActions(final String componentId, final IModel<T> model) {
                 final T taskTO = model.getObject();
 
                 final ActionLinksPanel.Builder<T> panel = ActionLinksPanel.<T>builder().
@@ -260,7 +258,7 @@ public abstract class SchedTaskDirectoryPanel<T extends SchedTaskTO>
                             }
                         }, ActionLink.ActionType.DELETE, StandardEntitlement.TASK_DELETE);
 
-                addFurtherAcions(panel, model);
+                addFurtherActions(panel, model);
 
                 return panel.build(componentId, model.getObject());
             }
@@ -286,7 +284,7 @@ public abstract class SchedTaskDirectoryPanel<T extends SchedTaskTO>
         return columns;
     }
 
-    protected void addFurtherAcions(final ActionLinksPanel.Builder<T> panel, final IModel<T> model) {
+    protected void addFurtherActions(final ActionLinksPanel.Builder<T> panel, final IModel<T> model) {
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/tasks/TransformersTogglePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/TransformersTogglePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/TransformersTogglePanel.java
deleted file mode 100644
index 72c2bd8..0000000
--- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/TransformersTogglePanel.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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 org.apache.syncope.client.console.tasks;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.console.SyncopeConsoleSession;
-import org.apache.syncope.client.console.panels.TogglePanel;
-import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
-import org.apache.syncope.common.lib.to.MappingItemTO;
-import org.apache.wicket.Component;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
-import org.apache.wicket.markup.html.WebMarkupContainer;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.markup.html.form.IChoiceRenderer;
-import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.LoadableDetachableModel;
-import org.apache.wicket.model.util.ListModel;
-
-public class TransformersTogglePanel extends TogglePanel<Serializable> {
-
-    private static final long serialVersionUID = -3195479265440591519L;
-
-    private Component container;
-
-    private MappingItemTO mapItem;
-
-    public TransformersTogglePanel(final WebMarkupContainer container) {
-        super("outer", "transformersTogglePanel");
-        this.container = container;
-
-        final LoadableDetachableModel<List<String>> model = new LoadableDetachableModel<List<String>>() {
-
-            private static final long serialVersionUID = 5275935387613157437L;
-
-            @Override
-            protected List<String> load() {
-                // [!] this is required to disable changed with close button
-                return mapItem == null
-                        ? Collections.<String>emptyList()
-                        : new ArrayList<>(mapItem.getMappingItemTransformerClassNames());
-            }
-        };
-
-        final Form<?> form = new Form<>("form");
-        addInnerObject(form);
-
-        form.add(new AjaxPalettePanel.Builder<String>().setAllowOrder(true).setRenderer(new IChoiceRenderer<String>() {
-
-            private static final long serialVersionUID = 3464376099975468136L;
-
-            private static final int MAX_LENGTH = 50;
-
-            @Override
-            public Object getDisplayValue(final String object) {
-                if (object.length() > MAX_LENGTH) {
-                    return "..." + object.substring(object.length() - MAX_LENGTH);
-                } else {
-                    return object;
-                }
-            }
-
-            @Override
-            public String getIdValue(final String object, final int index) {
-                return object;
-            }
-
-            @Override
-            public String getObject(final String id, final IModel<? extends List<? extends String>> choices) {
-                return id;
-            }
-        }).build(
-                "classes",
-                model,
-                new ListModel<>(
-                        new ArrayList<>(SyncopeConsoleSession.get().getPlatformInfo().getMappingItemTransformers()))).
-                hideLabel().setEnabled(true).setOutputMarkupId(true));
-
-        form.add(new AjaxSubmitLink("submit", form) {
-
-            private static final long serialVersionUID = 5538299138211283825L;
-
-            @Override
-            public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
-                toggle(target, false);
-
-                // [!] this is required to disable changed with close button
-                mapItem.getMappingItemTransformerClassNames().clear();
-                mapItem.getMappingItemTransformerClassNames().addAll(model.getObject());
-
-                target.add(TransformersTogglePanel.this.container);
-            }
-
-        });
-    }
-
-    public TransformersTogglePanel setMappingItem(final AjaxRequestTarget target, final MappingItemTO mapItem) {
-        this.mapItem = mapItem;
-        setHeader(target, StringUtils.EMPTY);
-        return this;
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
index 31a5d9f..5e4667a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
@@ -101,7 +101,7 @@ public class AjaxTextFieldPanel extends FieldPanel<String> implements Cloneable
         }
     }
 
-    public FieldPanel<String> enableJextHelp() {
+    public FieldPanel<String> enableJexlHelp() {
         questionMarkJexlHelp.setVisible(true);
         return this;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/widgets/JEXLTransformerWidget.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/widgets/JEXLTransformerWidget.java b/client/console/src/main/java/org/apache/syncope/client/console/widgets/JEXLTransformerWidget.java
new file mode 100644
index 0000000..a4dec3d
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/widgets/JEXLTransformerWidget.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.client.console.widgets;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.image.Icon;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconTypeBuilder;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.wizards.resources.JEXLTransformersTogglePanel;
+import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.markup.html.link.AbstractLink;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.util.ListModel;
+
+public class JEXLTransformerWidget extends AlertWidget<String> {
+
+    private static final long serialVersionUID = 7667120094526529934L;
+
+    private final MappingItemTO mapItem;
+
+    private final JEXLTransformersTogglePanel transformers;
+
+    public JEXLTransformerWidget(
+            final String id,
+            final MappingItemTO mapItem,
+            final JEXLTransformersTogglePanel transformers) {
+
+        super(id);
+        setOutputMarkupId(true);
+
+        this.mapItem = mapItem;
+        this.transformers = transformers;
+        
+        this.latestAlertsList.setVisible(false);
+    }
+
+    @Override
+    protected IModel<List<String>> getLatestAlerts() {
+        return new ListModel<String>() {
+
+            private static final long serialVersionUID = -2583290457773357445L;
+
+            @Override
+            public List<String> getObject() {
+                List<String> result = new ArrayList<>();
+                if (StringUtils.isNotBlank(mapItem.getPropagationJEXLTransformer())) {
+                    result.add(mapItem.getPropagationJEXLTransformer());
+                }
+                if (StringUtils.isNotBlank(mapItem.getPullJEXLTransformer())) {
+                    result.add(mapItem.getPullJEXLTransformer());
+                }
+                return result;
+            }
+        };
+    }
+
+    @Override
+    protected AbstractLink getEventsLink(final String linkid) {
+        return new AjaxLink<String>(linkid) {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                transformers.setMappingItem(target, JEXLTransformerWidget.this.mapItem);
+                transformers.toggle(target, true);
+            }
+        };
+    }
+
+    @Override
+    protected Icon getIcon(final String iconid) {
+        return new Icon(
+                iconid, FontAwesomeIconTypeBuilder.on(FontAwesomeIconTypeBuilder.FontAwesomeGraphic.repeat).build());
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget.java b/client/console/src/main/java/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget.java
index 5923417..6e363dd 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget.java
@@ -21,7 +21,7 @@ package org.apache.syncope.client.console.widgets;
 import de.agilecoders.wicket.core.markup.html.bootstrap.image.Icon;
 import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconTypeBuilder;
 import java.util.List;
-import org.apache.syncope.client.console.tasks.TransformersTogglePanel;
+import org.apache.syncope.client.console.wizards.resources.MappingItemTransformersTogglePanel;
 import org.apache.syncope.common.lib.to.MappingItemTO;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.markup.html.AjaxLink;
@@ -35,12 +35,13 @@ public class MappingItemTransformerWidget extends AlertWidget<String> {
 
     private final MappingItemTO mapItem;
 
-    private final TransformersTogglePanel transformers;
+    private final MappingItemTransformersTogglePanel transformers;
 
     public MappingItemTransformerWidget(
             final String id,
             final MappingItemTO mapItem,
-            final TransformersTogglePanel transformers) {
+            final MappingItemTransformersTogglePanel transformers) {
+
         super(id);
         this.mapItem = mapItem;
         this.transformers = transformers;

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
index 05f9794..7b4f4ce 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
@@ -44,7 +44,7 @@ public class GroupDetails extends Details<GroupTO> {
         final AjaxTextFieldPanel name = new AjaxTextFieldPanel("name", "name",
                 new PropertyModel<String>(groupTO, "name"), false);
         if (templateMode) {
-            name.enableJextHelp();
+            name.enableJexlHelp();
         } else {
             name.addRequiredLabel();
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
index 29e357b..39d9446 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
@@ -251,7 +251,7 @@ public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> {
                 panel = new AjaxTextFieldPanel("panel", schemaTO.getKey(), new Model<String>(), false);
 
                 if (jexlHelp) {
-                    AjaxTextFieldPanel.class.cast(panel).enableJextHelp();
+                    AjaxTextFieldPanel.class.cast(panel).enableJexlHelp();
                 }
 
                 if (required) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserDetails.java
index 166f94d..ac02a6e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserDetails.java
@@ -62,7 +62,7 @@ public class UserDetails extends Details<UserTO> {
                 "username", "username", new PropertyModel<String>(userTO, "username"), false);
 
         if (templateMode) {
-            username.enableJextHelp();
+            username.enableJexlHelp();
         } else {
             username.addRequiredLabel();
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/VirAttrs.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/VirAttrs.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/VirAttrs.java
index dd67e42..ea05da8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/VirAttrs.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/VirAttrs.java
@@ -73,7 +73,7 @@ public class VirAttrs extends AbstractAttrs<VirSchemaTO> {
                         = new AjaxTextFieldPanel("panel", attrTO.getSchema(), new Model<String>(), false);
 
                 if (mode == AjaxWizard.Mode.TEMPLATE) {
-                    item.add(panel.enableJextHelp().setEnabled(!attrTO.isReadonly()));
+                    item.add(panel.enableJexlHelp().setEnabled(!attrTO.isReadonly()));
                 } else {
                     item.add(new MultiFieldPanel.Builder<>(
                             new PropertyModel<List<String>>(attrTO, "values")).build(

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.java
new file mode 100644
index 0000000..d777af5
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.client.console.wizards.resources;
+
+import java.io.Serializable;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.panels.TogglePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+
+public class JEXLTransformersTogglePanel extends TogglePanel<Serializable> {
+
+    private static final long serialVersionUID = -1284019117452782479L;
+
+    private final AjaxTextFieldPanel propagationJEXLTransformer;
+
+    private final AjaxTextFieldPanel pullJEXLTransformer;
+
+    public JEXLTransformersTogglePanel(final WebMarkupContainer container) {
+        super("outer", "jexlTransformersTogglePanel");
+
+        Form<?> form = new Form<>("form");
+        addInnerObject(form);
+
+        propagationJEXLTransformer = new AjaxTextFieldPanel(
+                "propagationJEXLTransformer",
+                "Propagation",
+                Model.of(""));
+        form.add(propagationJEXLTransformer.enableJexlHelp());
+
+        pullJEXLTransformer = new AjaxTextFieldPanel(
+                "pullJEXLTransformer",
+                "Pull",
+                Model.of(""));
+        form.add(pullJEXLTransformer.enableJexlHelp());
+
+        form.add(new AjaxSubmitLink("submit", form) {
+
+            private static final long serialVersionUID = 4617041491286858973L;
+
+            @Override
+            public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+                toggle(target, false);
+                target.add(container);
+            }
+        });
+    }
+
+    public JEXLTransformersTogglePanel setMappingItem(final AjaxRequestTarget target, final MappingItemTO mapItem) {
+        this.propagationJEXLTransformer.setNewModel(new PropertyModel<String>(mapItem, "propagationJEXLTransformer"));
+        this.pullJEXLTransformer.setNewModel(new PropertyModel<String>(mapItem, "pullJEXLTransformer"));
+        setHeader(target, StringUtils.EMPTY);
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.java
new file mode 100644
index 0000000..4889c2b
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.syncope.client.console.wizards.resources;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.panels.TogglePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.util.ListModel;
+
+public class MappingItemTransformersTogglePanel extends TogglePanel<Serializable> {
+
+    private static final long serialVersionUID = -3195479265440591519L;
+
+    private MappingItemTO mapItem;
+
+    public MappingItemTransformersTogglePanel(final WebMarkupContainer container) {
+        super("outer", "mappingItemTransformersTogglePanel");
+
+        final LoadableDetachableModel<List<String>> model = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<String> load() {
+                // [!] this is required to disable changed with close button
+                return mapItem == null
+                        ? Collections.<String>emptyList()
+                        : new ArrayList<>(mapItem.getMappingItemTransformerClassNames());
+            }
+        };
+
+        Form<?> form = new Form<>("form");
+        addInnerObject(form);
+
+        form.add(new AjaxPalettePanel.Builder<String>().setAllowOrder(true).setRenderer(new IChoiceRenderer<String>() {
+
+            private static final long serialVersionUID = 3464376099975468136L;
+
+            private static final int MAX_LENGTH = 50;
+
+            @Override
+            public Object getDisplayValue(final String object) {
+                if (object.length() > MAX_LENGTH) {
+                    return "..." + object.substring(object.length() - MAX_LENGTH);
+                } else {
+                    return object;
+                }
+            }
+
+            @Override
+            public String getIdValue(final String object, final int index) {
+                return object;
+            }
+
+            @Override
+            public String getObject(final String id, final IModel<? extends List<? extends String>> choices) {
+                return id;
+            }
+        }).build(
+                "classes",
+                model,
+                new ListModel<>(
+                        new ArrayList<>(SyncopeConsoleSession.get().getPlatformInfo().getMappingItemTransformers()))).
+                hideLabel().setEnabled(true).setOutputMarkupId(true));
+
+        form.add(new AjaxSubmitLink("submit", form) {
+
+            private static final long serialVersionUID = 5538299138211283825L;
+
+            @Override
+            public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+                toggle(target, false);
+
+                // [!] this is required to disable changed with close button
+                mapItem.getMappingItemTransformerClassNames().clear();
+                mapItem.getMappingItemTransformerClassNames().addAll(model.getObject());
+
+                target.add(container);
+            }
+
+        });
+    }
+
+    public MappingItemTransformersTogglePanel setMappingItem(
+            final AjaxRequestTarget target, final MappingItemTO mapItem) {
+
+        this.mapItem = mapItem;
+        setHeader(target, StringUtils.EMPTY);
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ProvisionWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ProvisionWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ProvisionWizardBuilder.java
index 6f5badb..e342659 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ProvisionWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ProvisionWizardBuilder.java
@@ -28,7 +28,6 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.panels.ProvisionAuxClassesPanel;
 import org.apache.syncope.client.console.rest.AnyTypeRestClient;
-import org.apache.syncope.client.console.tasks.TransformersTogglePanel;
 import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
@@ -239,12 +238,17 @@ public class ProvisionWizardBuilder extends AjaxWizardBuilder<ProvisionTO> imple
         wizardModel.add(new ObjectType(modelObject));
         wizardModel.add(new AuxClasses(modelObject));
 
-        final Mapping mapping = new Mapping(modelObject);
+        Mapping mapping = new Mapping(modelObject);
         mapping.setOutputMarkupId(true);
+
+        MappingItemTransformersTogglePanel mapItemTransformers = new MappingItemTransformersTogglePanel(mapping);
+        addOuterObject(mapItemTransformers);
+        JEXLTransformersTogglePanel jexlTransformers = new JEXLTransformersTogglePanel(mapping);
+        addOuterObject(jexlTransformers);
+        mapping.add(new ResourceMappingPanel(
+                "mapping", resourceTO, modelObject, mapItemTransformers, jexlTransformers));
+
         wizardModel.add(mapping);
-        final TransformersTogglePanel transformers = new TransformersTogglePanel(mapping);
-        addOuterObject(transformers);
-        mapping.add(new ResourceMappingPanel("mapping", resourceTO, modelObject, transformers));
 
         wizardModel.add(new ConnObjectLink(modelObject));
         return wizardModel;

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
index fd6ca46..5020bd7 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
@@ -34,7 +34,6 @@ import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
 import org.apache.syncope.client.console.rest.AnyTypeRestClient;
 import org.apache.syncope.client.console.rest.ConnectorRestClient;
-import org.apache.syncope.client.console.tasks.TransformersTogglePanel;
 import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
@@ -42,6 +41,7 @@ import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPan
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.MappingPurposePanel;
+import org.apache.syncope.client.console.widgets.JEXLTransformerWidget;
 import org.apache.syncope.client.console.widgets.MappingItemTransformerWidget;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.AnyTypeTO;
@@ -109,11 +109,6 @@ public class ResourceMappingPanel extends Panel {
     private final ListView<MappingItemTO> mappings;
 
     /**
-     * External resource to be updated.
-     */
-    private final ResourceTO resourceTO;
-
-    /**
      * External resource provisioning configuration instance to be updated.
      */
     private final ProvisionTO provisionTO;
@@ -135,18 +130,21 @@ public class ResourceMappingPanel extends Panel {
      * Attribute Mapping Panel.
      *
      * @param id panel id
-     * @param resourceTO external resource to be updated.
-     * @param provisionTO external resource provisioning configuration instance.
+     * @param resourceTO external resource to be updated
+     * @param provisionTO external resource provisioning configuration instance
+     * @param mapItemTransformers mapping item transformers toggle panel
+     * @param jexlTransformers JEXL transformers toggle panel
      */
     public ResourceMappingPanel(
             final String id,
             final ResourceTO resourceTO,
             final ProvisionTO provisionTO,
-            final TransformersTogglePanel transformers) {
+            final MappingItemTransformersTogglePanel mapItemTransformers,
+            final JEXLTransformersTogglePanel jexlTransformers) {
+
         super(id);
         setOutputMarkupId(true);
 
-        this.resourceTO = resourceTO;
         this.provisionTO = provisionTO == null ? new ProvisionTO() : provisionTO;
         if (provisionTO == null) {
             getMapping().getItems().clear();
@@ -292,10 +290,17 @@ public class ResourceMappingPanel extends Panel {
                 // -------------------------------
 
                 //--------------------------------
-                // Mapping item transformer
+                // JEXL transformers
+                // -------------------------------
+                item.add(new JEXLTransformerWidget(
+                        "jexlTransformers", mapItem, jexlTransformers).setRenderBodyOnly(true));
+                // -------------------------------
+
+                //--------------------------------
+                // Mapping item transformers
                 // -------------------------------
                 item.add(new MappingItemTransformerWidget(
-                        "transformers", mapItem, transformers).setRenderBodyOnly(true));
+                        "mappingItemTransformers", mapItem, mapItemTransformers).setRenderBodyOnly(true));
                 // -------------------------------
 
                 //--------------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css b/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
index 267b425..ae152d9 100644
--- a/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
+++ b/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
@@ -734,6 +734,10 @@ li.todoitem a {
   cursor: pointer;
 }
 
+.popover-content {
+  color: black;
+}
+
 .form-palette {
   display: inline-block;
   width: 119%;
@@ -821,39 +825,44 @@ END - Alert widget onside menu
 /**
 START - Transformers toggle panel
 */
-div#transformersTogglePanel {
+div.transformersTogglePanel {
   background-color: rgba(140, 140, 140, 0.99) !important;
   width: 1000px !important;
 }
 
-div#transformersContainer {
+div.transformersContainer {
   padding: 15px;
 }
 
-div#transformersContainer input {
+div.transformersContainer input {
   background-color: rgba(200, 200, 200, 0.60) !important;
 }
 
-div#transformersContainer #footer {
+div.transformersContainer #footer {
   clear: both;
   display: block;
   text-align: right;
+  margin-top: 10px;
 }
 
-div#transformersContainer #body {
+div.transformersContainer #body {
   clear: both;
   display: block;
 }
 
-div#transformersContainer #body select {
+div.mappingItemTransformersContainer #body select {
   border: 1px solid #ccc !important;
   background: rgba(240, 240, 240, 0.95) !important
 }
 
-div#transformersContainer #body a {
+div.mappingItemTransformersContainer #body a {
   color: #ccc !important;
   cursor: pointer !important;
 }
+
+div#jexlTransformersTogglePanel {
+  right: 400px;
+}
 /**
 END - Transformers toggle panel
 */

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel.html
deleted file mode 100644
index 2193a6a..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you 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.
--->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <wicket:extend>
-    <div id="transformersContainer">
-      <form wicket:id="form">
-        <div id="body">
-          <span wicket:id="classes"/>
-        </div>
-        <div id="footer">
-          <input type="button" wicket:id="submit" class="btn" wicket:message="value:finish"></input>
-        </div>
-      </form>
-    </div>
-  </wicket:extend>
-</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel.properties
deleted file mode 100644
index e3d6fd7..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-finish=Finish
-palette.available=Available Mapping Item Transformers
-palette.selected=Selected Transformers

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_it.properties
deleted file mode 100644
index 827394e..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_it.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-finish=Fine
-palette.available=Mapping Item Transformer Disponibili
-palette.selected=Transformer Selezionati

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_pt_BR.properties
deleted file mode 100644
index e3d6fd7..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_pt_BR.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-finish=Finish
-palette.available=Available Mapping Item Transformers
-palette.selected=Selected Transformers

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_ru.properties
deleted file mode 100644
index e3d6fd7..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/tasks/TransformersTogglePanel_ru.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
-finish=Finish
-palette.available=Available Mapping Item Transformers
-palette.selected=Selected Transformers

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget.properties b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget.properties
new file mode 100644
index 0000000..09aa967
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+alerts.view.all=View All JEXL Tranformers
+summary=${number} configured expression(s)

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_it.properties
new file mode 100644
index 0000000..aa754d7
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_it.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+alerts.view.all=Tutti i Transformer JEXL
+summary=${number} espressione/i configurata/e

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_pt_BR.properties
new file mode 100644
index 0000000..09aa967
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_pt_BR.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+alerts.view.all=View All JEXL Tranformers
+summary=${number} configured expression(s)

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_ru.properties
new file mode 100644
index 0000000..5d85836
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/JEXLTransformerWidget_ru.properties
@@ -0,0 +1,21 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+# approvals.view.all=\u00d0\u009f\u00d0\u00be\u00d1\u0081\u00d0\u00bc\u00d0\u00be\u00d1\u0082\u00d1\u0080\u00d0\u00b5\u00d1\u0082\u00d1\u008c \u00d0\u00b2\u00d1\u0081\u00d0\u00b5 \u00d0\u00b7\u00d0\u00b0\u00d1\u008f\u00d0\u00b2\u00d0\u00ba\u00d0\u00b8
+alerts.view.all=View All JEXL Tranformers
+# summary=${number} \u00d0\u00be\u00d0\u00b6\u00d0\u00b8\u00d0\u00b4\u00d0\u00b0\u00d1\u008e\u00d1\u0082 \u00d1\u0081\u00d0\u00be\u00d0\u00b3\u00d0\u00bb\u00d0\u00b0\u00d1\u0081\u00d0\u00be\u00d0\u00b2\u00d0\u00b0\u00d0\u00bd\u00d0\u00b8\u00d1\u008f
+summary=${number} configured expression(s)

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget.properties b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget.properties
index d12923b..5c2d15d 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget.properties
@@ -14,5 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-alerts.view.all=View All Mapping Tranformers
+alerts.view.all=View All Mapping Item Tranformers
 summary=${number} selected transformer(s)

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_it.properties
index 5e85664..8e23aef 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_it.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_it.properties
@@ -14,5 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-alerts.view.all=Tutti i Mapping Transformer
+alerts.view.all=View All Mapping Item Tranformers
 summary=${number} transformer selezionati

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_pt_BR.properties
index d12923b..0fd94d7 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_pt_BR.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_pt_BR.properties
@@ -14,5 +14,5 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-alerts.view.all=View All Mapping Tranformers
-summary=${number} selected transformer(s)
+alerts.view.all=View All Mapping Item Tranformers
+summary=${number} JEXL transforming expression(s)

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_ru.properties
index 3418dad..16e78be 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_ru.properties
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/MappingItemTransformerWidget_ru.properties
@@ -16,6 +16,6 @@
 # under the License.
 #
 # approvals.view.all=\u00d0\u009f\u00d0\u00be\u00d1\u0081\u00d0\u00bc\u00d0\u00be\u00d1\u0082\u00d1\u0080\u00d0\u00b5\u00d1\u0082\u00d1\u008c \u00d0\u00b2\u00d1\u0081\u00d0\u00b5 \u00d0\u00b7\u00d0\u00b0\u00d1\u008f\u00d0\u00b2\u00d0\u00ba\u00d0\u00b8
-alerts.view.all=View All Mapping Tranformers
+alerts.view.all=View All Mapping Item Tranformers
 # summary=${number} \u00d0\u00be\u00d0\u00b6\u00d0\u00b8\u00d0\u00b4\u00d0\u00b0\u00d1\u008e\u00d1\u0082 \u00d1\u0081\u00d0\u00be\u00d0\u00b3\u00d0\u00bb\u00d0\u00b0\u00d1\u0081\u00d0\u00be\u00d0\u00b2\u00d0\u00b0\u00d0\u00bd\u00d0\u00b8\u00d1\u008f
 summary=${number} selected transformer(s)

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.html
new file mode 100644
index 0000000..142f91a
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/JEXLTransformersTogglePanel.html
@@ -0,0 +1,33 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <div id="jexlTransformersContainer" class="transformersContainer">
+      <form wicket:id="form">
+        <div id="body">
+          <span wicket:id="propagationJEXLTransformer"/>
+          <span wicket:id="pullJEXLTransformer"/>
+        </div>
+        <div id="footer">
+          <input type="button" wicket:id="submit" class="btn" wicket:message="value:finish"></input>
+        </div>
+      </form>
+    </div>
+  </wicket:extend>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.html
new file mode 100644
index 0000000..8983a41
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.html
@@ -0,0 +1,32 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <div id="mappingItemTransformersContainer" class="transformersContainer">
+      <form wicket:id="form">
+        <div id="body">
+          <span wicket:id="classes"/>
+        </div>
+        <div id="footer">
+          <input type="button" wicket:id="submit" class="btn" wicket:message="value:finish"></input>
+        </div>
+      </form>
+    </div>
+  </wicket:extend>
+</html>

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.properties
new file mode 100644
index 0000000..06d3702
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+finish=Finish
+palette.available=Available Mapping Item Transformers
+palette.selected=Selected Mapping Item Transformers

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_it.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_it.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_it.properties
new file mode 100644
index 0000000..9e80b99
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_it.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+finish=Fine
+palette.available=Mapping Item Transformer Disponibili
+palette.selected=Mapping Item Transformer Selezionati

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_pt_BR.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_pt_BR.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_pt_BR.properties
new file mode 100644
index 0000000..d5a72dc
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_pt_BR.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+finish=Finish
+palette.available=Available Mapping Item Transformers
+palette.selected=Mapping Item

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_ru.properties
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_ru.properties b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_ru.properties
new file mode 100644
index 0000000..d5a72dc
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/MappingItemTransformersTogglePanel_ru.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+finish=Finish
+palette.available=Available Mapping Item Transformers
+palette.selected=Mapping Item

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.html
index b087541..2aa106b 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.html
@@ -31,6 +31,7 @@ under the License.
               <th><wicket:message key="intMappingTypes"/></th>
               <th><wicket:message key="intAttrNames"/></th>
               <th><wicket:message key="extAttrNames"/></th>
+              <th><i class="fa fa-repeat"></i></th>
               <th><i class="fa fa-magic"></i></th>
               <th>
                 <wicket:message key="mandatoryCondition"/>
@@ -56,7 +57,12 @@ under the License.
               </td>
               <td>
                 <div class="alert-widget dropdown tasks-menu">
-                  <span wicket:id="transformers">[Mapping Item Transformes]</span>
+                  <span wicket:id="jexlTransformers">[JEXL Transformers]</span>
+                </div>
+              </td>
+              <td>
+                <div class="alert-widget dropdown tasks-menu">
+                  <span wicket:id="mappingItemTransformers">[Mapping Item Transformers]</span>
                 </div>
               </td>
               <td>

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
index 84ba6fb..696941d 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
@@ -73,6 +73,16 @@ public class MappingItemTO extends AbstractBaseBean implements EntityTO {
      */
     private MappingPurpose purpose;
 
+    /**
+     * (Optional) JEXL expression to apply to values before propagation.
+     */
+    private String propagationJEXLTransformer;
+
+    /**
+     * (Optional) JEXL expression to apply to values before pull.
+     */
+    private String pullJEXLTransformer;
+
     private final List<String> mappingItemTransformerClassNames = new ArrayList<>();
 
     public boolean isConnObjectKey() {
@@ -141,6 +151,22 @@ public class MappingItemTO extends AbstractBaseBean implements EntityTO {
         this.purpose = purpose;
     }
 
+    public String getPropagationJEXLTransformer() {
+        return propagationJEXLTransformer;
+    }
+
+    public void setPropagationJEXLTransformer(final String propagationJEXLTransformer) {
+        this.propagationJEXLTransformer = propagationJEXLTransformer;
+    }
+
+    public String getPullJEXLTransformer() {
+        return pullJEXLTransformer;
+    }
+
+    public void setPullJEXLTransformer(final String pullJEXLTransformer) {
+        this.pullJEXLTransformer = pullJEXLTransformer;
+    }
+
     @XmlElementWrapper(name = "mappingItemTransformerClassNames")
     @XmlElement(name = "className")
     @JsonProperty("mappingItemTransformerClassNames")

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
index 53b0a56..beff515 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/init/ClassPathScanImplementationLookup.java
@@ -55,6 +55,7 @@ import org.springframework.util.ClassUtils;
 import org.apache.syncope.core.provisioning.api.pushpull.ReconciliationFilterBuilder;
 import org.apache.syncope.core.provisioning.api.pushpull.PullCorrelationRule;
 import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
+import org.apache.syncope.core.provisioning.java.data.JEXLMappingItemTransformer;
 
 /**
  * Cache class names for all implementations of Syncope interfaces found in classpath, for later usage.
@@ -136,7 +137,9 @@ public class ClassPathScanImplementationLookup implements ImplementationLookup {
                     }
                 }
 
-                if (MappingItemTransformer.class.isAssignableFrom(clazz) && !isAbsractClazz) {
+                if (MappingItemTransformer.class.isAssignableFrom(clazz) && !isAbsractClazz
+                        && !clazz.equals(JEXLMappingItemTransformer.class)) {
+
                     classNames.get(Type.MAPPING_ITEM_TRANSFORMER).add(clazz.getName());
                 }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/LinkingMappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/LinkingMappingItem.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/LinkingMappingItem.java
index 85b7d5a..6fb320f 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/LinkingMappingItem.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/LinkingMappingItem.java
@@ -134,6 +134,26 @@ public class LinkingMappingItem implements MappingItem {
     }
 
     @Override
+    public String getPropagationJEXLTransformer() {
+        return null;
+    }
+
+    @Override
+    public void setPropagationJEXLTransformer(final String propagationJEXLTransformer) {
+        // RO instance, nothing to do
+    }
+
+    @Override
+    public String getPullJEXLTransformer() {
+        return null;
+    }
+
+    @Override
+    public void setPullJEXLTransformer(final String pullJEXLTransformer) {
+        // RO instance, nothing to do
+    }
+
+    @Override
     public List<String> getMappingItemTransformerClassNames() {
         return Collections.emptyList();
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
index abbf69c..af751e2 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/resource/MappingItem.java
@@ -57,6 +57,14 @@ public interface MappingItem extends Entity {
 
     void setPassword(boolean password);
 
+    String getPropagationJEXLTransformer();
+
+    void setPropagationJEXLTransformer(String propagationJEXLTransformer);
+
+    String getPullJEXLTransformer();
+
+    void setPullJEXLTransformer(String pullJEXLTransformer);
+
     List<String> getMappingItemTransformerClassNames();
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
index f3d2702..438994f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
@@ -95,6 +95,18 @@ public class JPAMappingItem extends AbstractGeneratedKeyEntity implements Mappin
     private MappingPurpose purpose;
 
     /**
+     * (Optional) JEXL expression to apply to values before propagation.
+     */
+    @Column(name = "propJEXL")
+    private String propagationJEXLTransformer;
+
+    /**
+     * (Optional) JEXL expression to apply to values before pull.
+     */
+    @Column(name = "pullJEXL")
+    private String pullJEXLTransformer;
+
+    /**
      * (Optional) classes for MappingItem transformation.
      */
     @ElementCollection(fetch = FetchType.EAGER)
@@ -224,6 +236,26 @@ public class JPAMappingItem extends AbstractGeneratedKeyEntity implements Mappin
     }
 
     @Override
+    public String getPropagationJEXLTransformer() {
+        return propagationJEXLTransformer;
+    }
+
+    @Override
+    public void setPropagationJEXLTransformer(final String propagationJEXLTransformer) {
+        this.propagationJEXLTransformer = propagationJEXLTransformer;
+    }
+
+    @Override
+    public String getPullJEXLTransformer() {
+        return pullJEXLTransformer;
+    }
+
+    @Override
+    public void setPullJEXLTransformer(final String pullJEXLTransformer) {
+        this.pullJEXLTransformer = pullJEXLTransformer;
+    }
+
+    @Override
     public List<String> getMappingItemTransformerClassNames() {
         return mappingItemTransformerClassNames;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5ee30a66/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java
index 18d998b..db66766 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/data/MappingItemTransformer.java
@@ -19,7 +19,10 @@
 package org.apache.syncope.core.provisioning.api.data;
 
 import java.util.List;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 
 /**
  * Transforms values to be propagated to (or pulling from) external resources right before they leave (or enter)
@@ -32,16 +35,26 @@ public interface MappingItemTransformer {
     /**
      * Invoked while preparing attribute values to be sent out to external resource during propagation.
      *
+     * @param mappingItem mapping item
+     * @param anys any objects
      * @param values original values
      * @return transformed values
      */
-    List<PlainAttrValue> beforePropagation(List<PlainAttrValue> values);
+    List<PlainAttrValue> beforePropagation(
+            MappingItem mappingItem,
+            List<Any<?>> anys,
+            List<PlainAttrValue> values);
 
     /**
      * Invoked while reading attribute values from external resource during pull.
      *
+     * @param mappingItem mapping item
+     * @param anyTO any object
      * @param values original values
      * @return transformed values
      */
-    List<Object> beforePull(List<Object> values);
+    List<Object> beforePull(
+            MappingItem mappingItem,
+            AnyTO anyTO,
+            List<Object> values);
 }