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 2013/11/12 09:55:32 UTC

svn commit: r1540975 - in /syncope/trunk: common/src/main/java/org/apache/syncope/common/types/ core/src/main/java/org/apache/syncope/core/connid/ core/src/main/java/org/apache/syncope/core/persistence/beans/ core/src/main/java/org/apache/syncope/core/...

Author: ilgrosso
Date: Tue Nov 12 08:55:31 2013
New Revision: 1540975

URL: http://svn.apache.org/r1540975
Log:
[SYNCOPE-435] Merge from 1_1_X

Modified:
    syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractDerAttr.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/PropagationTaskExecutor.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/ResourceDataBinder.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/SchemaDataBinder.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/util/AttributableUtil.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/util/JexlUtil.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java
    syncope/trunk/core/src/main/resources/syncopeContext.xml
    syncope/trunk/core/src/test/java/org/apache/syncope/core/notification/NotificationTest.java
    syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java

Modified: syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/types/ResourceOperation.java Tue Nov 12 08:55:31 2013
@@ -18,16 +18,10 @@
  */
 package org.apache.syncope.common.types;
 
-import javax.xml.bind.annotation.XmlEnum;
-
-@XmlEnum
 public enum ResourceOperation {
 
     CREATE,
     UPDATE,
-    DELETE;
+    DELETE
 
-    public static ResourceOperation fromString(final String value) {
-        return ResourceOperation.valueOf(value.toUpperCase());
-    }
 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/connid/ConnObjectUtil.java Tue Nov 12 08:55:31 2013
@@ -86,12 +86,6 @@ public class ConnObjectUtil {
     private static final Logger LOG = LoggerFactory.getLogger(ConnObjectUtil.class);
 
     /**
-     * JEXL engine for evaluating connector's account link.
-     */
-    @Autowired
-    private JexlUtil jexlUtil;
-
-    /**
      * User data binder.
      */
     @Autowired
@@ -350,14 +344,14 @@ public class ConnObjectUtil {
         if (template != null) {
             if (template instanceof UserTO) {
                 if (StringUtils.isNotBlank(((UserTO) template).getUsername())) {
-                    String evaluated = jexlUtil.evaluate(((UserTO) template).getUsername(), attributableTO);
+                    String evaluated = JexlUtil.evaluate(((UserTO) template).getUsername(), attributableTO);
                     if (StringUtils.isNotBlank(evaluated)) {
                         ((UserTO) attributableTO).setUsername(evaluated);
                     }
                 }
 
                 if (StringUtils.isNotBlank(((UserTO) template).getPassword())) {
-                    String evaluated = jexlUtil.evaluate(((UserTO) template).getPassword(), attributableTO);
+                    String evaluated = JexlUtil.evaluate(((UserTO) template).getPassword(), attributableTO);
                     if (StringUtils.isNotBlank(evaluated)) {
                         ((UserTO) attributableTO).setPassword(evaluated);
                     }
@@ -378,7 +372,7 @@ public class ConnObjectUtil {
             }
             if (template instanceof RoleTO) {
                 if (StringUtils.isNotBlank(((RoleTO) template).getName())) {
-                    String evaluated = jexlUtil.evaluate(((RoleTO) template).getName(), attributableTO);
+                    String evaluated = JexlUtil.evaluate(((RoleTO) template).getName(), attributableTO);
                     if (StringUtils.isNotBlank(evaluated)) {
                         ((RoleTO) attributableTO).setName(evaluated);
                     }
@@ -543,7 +537,7 @@ public class ConnObjectUtil {
                         final String accountId = attrUtil.getAccountIdItem(resource) == null
                                 ? null
                                 : MappingUtil.getAccountIdValue(
-                                owner, resource, attrUtil.getAccountIdItem(resource));
+                                        owner, resource, attrUtil.getAccountIdItem(resource));
 
                         if (StringUtils.isBlank(accountId)) {
                             throw new IllegalArgumentException("No AccountId found for " + resource.getName());
@@ -643,7 +637,7 @@ public class ConnObjectUtil {
 
         if (template.getValues() != null && !template.getValues().isEmpty()) {
             for (String value : template.getValues()) {
-                String evaluated = jexlUtil.evaluate(value, attributableTO);
+                String evaluated = JexlUtil.evaluate(value, attributableTO);
                 if (StringUtils.isNotBlank(evaluated)) {
                     result.getValues().add(evaluated);
                 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractDerAttr.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractDerAttr.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractDerAttr.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/AbstractDerAttr.java Tue Nov 12 08:55:31 2013
@@ -25,9 +25,7 @@ import javax.persistence.Id;
 import javax.persistence.MappedSuperclass;
 import org.apache.commons.jexl2.JexlContext;
 import org.apache.commons.jexl2.MapContext;
-import org.apache.syncope.core.util.ApplicationContextProvider;
 import org.apache.syncope.core.util.JexlUtil;
-import org.springframework.context.ConfigurableApplicationContext;
 
 @MappedSuperclass
 public abstract class AbstractDerAttr extends AbstractBaseBean {
@@ -48,16 +46,13 @@ public abstract class AbstractDerAttr ex
      * @return the value of this derived attribute
      */
     public String getValue(final Collection<? extends AbstractAttr> attributes) {
-        final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
-        final JexlUtil jexlUtil = context.getBean(JexlUtil.class);
-
         // Prepare context using user attributes
         final JexlContext jexlContext = new MapContext();
-        jexlUtil.addAttrsToContext(attributes, jexlContext);
-        jexlUtil.addFieldsToContext(getOwner(), jexlContext);
+        JexlUtil.addAttrsToContext(attributes, jexlContext);
+        JexlUtil.addFieldsToContext(getOwner(), jexlContext);
 
         // Evaluate expression using the context prepared before
-        return jexlUtil.evaluate(getSchema().getExpression(), jexlContext);
+        return JexlUtil.evaluate(getSchema().getExpression(), jexlContext);
     }
 
     public abstract <T extends AbstractAttributable> T getOwner();

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/beans/user/SyncopeUser.java Tue Nov 12 08:55:31 2013
@@ -72,7 +72,7 @@ public class SyncopeUser extends Abstrac
     @Id
     private Long id;
 
-    @NotNull
+    @NotNull(message = "Blank password")
     private String password;
 
     @Transient
@@ -122,7 +122,7 @@ public class SyncopeUser extends Abstrac
      * Username/Login.
      */
     @Column(unique = true)
-    @NotNull
+    @NotNull(message = "Blank username")
     private String username;
 
     /**

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/PropagationTaskExecutor.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/PropagationTaskExecutor.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/PropagationTaskExecutor.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/PropagationTaskExecutor.java Tue Nov 12 08:55:31 2013
@@ -31,6 +31,18 @@ import org.apache.syncope.core.persisten
 public interface PropagationTaskExecutor {
 
     /**
+     * Name for special propagation attribute used to indicate whether there are attributes, marked as mandatory in the
+     * mapping but not to be propagated.
+     */
+    String MANDATORY_MISSING_ATTR_NAME = "__MANDATORY_MISSING__";
+
+    /**
+     * Name for special propagation attribute used to indicate whether there are attributes, marked as mandatory in the
+     * mapping but about to be propagated as null or empty.
+     */
+    String MANDATORY_NULL_OR_EMPTY_ATTR_NAME = "__MANDATORY_NULL_OR_EMPTY__";
+
+    /**
      * Execute the given PropagationTask and returns the generated TaskExec.
      *
      * @param task to be executed

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/AbstractPropagationTaskExecutor.java Tue Nov 12 08:55:31 2013
@@ -18,10 +18,12 @@
  */
 package org.apache.syncope.core.propagation.impl;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.apache.commons.lang3.StringUtils;
@@ -125,6 +127,27 @@ public abstract class AbstractPropagatio
         // set of attributes to be propagated
         final Set<Attribute> attributes = new HashSet<Attribute>(task.getAttributes());
 
+        // check if there is any missing or null / empty mandatory attribute
+        List<Object> mandatoryAttrNames = new ArrayList<Object>();
+        Attribute mandatoryMissing = AttributeUtil.find(MANDATORY_MISSING_ATTR_NAME, task.getAttributes());
+        if (mandatoryMissing != null) {
+            attributes.remove(mandatoryMissing);
+
+            if (beforeObj == null) {
+                mandatoryAttrNames.addAll(mandatoryMissing.getValue());
+            }
+        }
+        Attribute mandatoryNullOrEmpty = AttributeUtil.find(MANDATORY_NULL_OR_EMPTY_ATTR_NAME, task.getAttributes());
+        if (mandatoryNullOrEmpty != null) {
+            attributes.remove(mandatoryNullOrEmpty);
+
+            mandatoryAttrNames.addAll(mandatoryNullOrEmpty.getValue());
+        }
+        if (!mandatoryAttrNames.isEmpty()) {
+            throw new IllegalArgumentException(
+                    "Not attempted because there are mandatory attributes without value(s): " + mandatoryAttrNames);
+        }
+
         if (beforeObj == null) {
             // 1. get accountId
             final String accountId = task.getAccountId();

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/LDAPMembershipPropagationActions.java Tue Nov 12 08:55:31 2013
@@ -55,9 +55,6 @@ public class LDAPMembershipPropagationAc
     @Autowired
     protected UserDAO userDAO;
 
-    @Autowired
-    protected JexlUtil jexlUtil;
-
     /**
      * Allows easy subclassing for the ConnId AD connector bundle.
      *
@@ -83,11 +80,11 @@ public class LDAPMembershipPropagationAc
                         LOG.debug("Evaluating accountLink for {}", role);
 
                         final JexlContext jexlContext = new MapContext();
-                        jexlUtil.addFieldsToContext(role, jexlContext);
-                        jexlUtil.addAttrsToContext(role.getAttrs(), jexlContext);
-                        jexlUtil.addDerAttrsToContext(role.getDerAttrs(), role.getAttrs(), jexlContext);
+                        JexlUtil.addFieldsToContext(role, jexlContext);
+                        JexlUtil.addAttrsToContext(role.getAttrs(), jexlContext);
+                        JexlUtil.addDerAttrsToContext(role.getDerAttrs(), role.getAttrs(), jexlContext);
                         final String roleAccountLink =
-                                jexlUtil.evaluate(task.getResource().getRmapping().getAccountLink(), jexlContext);
+                                JexlUtil.evaluate(task.getResource().getRmapping().getAccountLink(), jexlContext);
                         LOG.debug("AccountLink for {} is '{}'", role, roleAccountLink);
                         if (StringUtils.isNotBlank(roleAccountLink)) {
                             roleAccountLinks.add(roleAccountLink);

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java Tue Nov 12 08:55:31 2013
@@ -46,11 +46,13 @@ import org.apache.syncope.core.persisten
 import org.apache.syncope.core.persistence.dao.NotFoundException;
 import org.apache.syncope.core.persistence.dao.ResourceDAO;
 import org.apache.syncope.core.propagation.PropagationByResource;
+import org.apache.syncope.core.propagation.PropagationTaskExecutor;
 import org.apache.syncope.core.rest.controller.UnauthorizedRoleException;
 import org.apache.syncope.core.rest.data.AbstractAttributableDataBinder;
 import org.apache.syncope.core.rest.data.RoleDataBinder;
 import org.apache.syncope.core.rest.data.UserDataBinder;
 import org.apache.syncope.core.util.AttributableUtil;
+import org.apache.syncope.core.util.JexlUtil;
 import org.apache.syncope.core.util.MappingUtil;
 import org.apache.syncope.core.util.VirAttrCache;
 import org.apache.syncope.core.workflow.WorkflowResult;
@@ -488,6 +490,7 @@ public class PropagationManager {
      * Prepare attributes for sending to a connector instance.
      *
      * @param <T> user / role
+     * @param attrUtil user / role
      * @param subject given user / role
      * @param password clear-text password
      * @param vAttrsToBeRemoved virtual attributes to be removed
@@ -496,9 +499,10 @@ public class PropagationManager {
      * @param resource target resource
      * @return account link + prepared attributes
      */
-    protected <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> prepareAttributes(final T subject,
-            final String password, final Set<String> vAttrsToBeRemoved,
-            final Map<String, AttributeMod> vAttrsToBeUpdated, final Boolean enable, final ExternalResource resource) {
+    protected <T extends AbstractAttributable> Map.Entry<String, Set<Attribute>> prepareAttributes(
+            final AttributableUtil attrUtil, final T subject, final String password,
+            final Set<String> vAttrsToBeRemoved, final Map<String, AttributeMod> vAttrsToBeUpdated,
+            final Boolean enable, final ExternalResource resource) {
 
         LOG.debug("Preparing resource attributes for {} on resource {} with attributes {}",
                 subject, resource, subject.getAttrs());
@@ -506,7 +510,6 @@ public class PropagationManager {
         Set<Attribute> attributes = new HashSet<Attribute>();
         String accountId = null;
 
-        final AttributableUtil attrUtil = AttributableUtil.getInstance(subject);
         for (AbstractMappingItem mapping : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
             LOG.debug("Processing schema {}", mapping.getIntAttrName());
 
@@ -515,6 +518,7 @@ public class PropagationManager {
                         && mapping.getIntMappingType() == IntMappingType.UserVirtualSchema)
                         || (attrUtil.getType() == AttributableType.ROLE
                         && mapping.getIntMappingType() == IntMappingType.RoleVirtualSchema)) {
+
                     LOG.debug("Expire entry cache {}-{}", subject.getId(), mapping.getIntAttrName());
                     virAttrCache.expire(attrUtil.getType(), subject.getId(), mapping.getIntAttrName());
                 }
@@ -527,8 +531,7 @@ public class PropagationManager {
                 }
 
                 if (preparedAttribute.getValue() != null) {
-                    final Attribute alreadyAdded = AttributeUtil.find(preparedAttribute.getValue().getName(),
-                            attributes);
+                    Attribute alreadyAdded = AttributeUtil.find(preparedAttribute.getValue().getName(), attributes);
 
                     if (alreadyAdded == null) {
                         attributes.add(preparedAttribute.getValue());
@@ -620,9 +623,35 @@ public class PropagationManager {
                     task.setPropagationMode(resource.getPropagationMode());
                     task.setOldAccountId(propByRes.getOldAccountId(resource.getName()));
 
-                    Map.Entry<String, Set<Attribute>> preparedAttrs = prepareAttributes(subject, password,
+                    Map.Entry<String, Set<Attribute>> preparedAttrs = prepareAttributes(attrUtil, subject, password,
                             vAttrsToBeRemoved, vAttrsToBeUpdated, enable, resource);
                     task.setAccountId(preparedAttrs.getKey());
+
+                    // Check if any of mandatory attributes (in the mapping) is missing or not received any value: 
+                    // if so, add special attributes that will be evaluated by PropagationTaskExecutor
+                    List<String> mandatoryMissing = new ArrayList<String>();
+                    List<String> mandatoryNullOrEmpty = new ArrayList<String>();
+                    for (AbstractMappingItem item : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+                        if (!item.isAccountid()
+                                && JexlUtil.evaluateMandatoryCondition(item.getMandatoryCondition(), subject)) {
+
+                            Attribute attr = AttributeUtil.find(item.getExtAttrName(), preparedAttrs.getValue());
+                            if (attr == null) {
+                                mandatoryMissing.add(item.getExtAttrName());
+                            } else if (attr.getValue() == null || attr.getValue().isEmpty()) {
+                                mandatoryNullOrEmpty.add(item.getExtAttrName());
+                            }
+                        }
+                    }
+                    if (!mandatoryMissing.isEmpty()) {
+                        preparedAttrs.getValue().add(AttributeBuilder.build(
+                                PropagationTaskExecutor.MANDATORY_MISSING_ATTR_NAME, mandatoryMissing));
+                    }
+                    if (!mandatoryNullOrEmpty.isEmpty()) {
+                        preparedAttrs.getValue().add(AttributeBuilder.build(
+                                PropagationTaskExecutor.MANDATORY_NULL_OR_EMPTY_ATTR_NAME, mandatoryNullOrEmpty));
+                    }
+
                     task.setAttributes(preparedAttrs.getValue());
 
                     tasks.add(task);

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/AbstractAttributableDataBinder.java Tue Nov 12 08:55:31 2013
@@ -25,8 +25,6 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
-import org.apache.commons.jexl2.JexlContext;
-import org.apache.commons.jexl2.MapContext;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.mod.AbstractAttributableMod;
 import org.apache.syncope.common.mod.AttributeMod;
@@ -138,9 +136,6 @@ public abstract class AbstractAttributab
     @Autowired
     protected PolicyDAO policyDAO;
 
-    @Autowired
-    private JexlUtil jexlUtil;
-
     @SuppressWarnings("unchecked")
     protected <T extends AbstractSchema> T getSchema(final String schemaName, final Class<T> reference) {
         T result = null;
@@ -239,17 +234,6 @@ public abstract class AbstractAttributab
         }
     }
 
-    private boolean evaluateMandatoryCondition(final String mandatoryCondition,
-            final AbstractAttributable attributable) {
-
-        JexlContext jexlContext = new MapContext();
-        jexlUtil.addAttrsToContext(attributable.getAttrs(), jexlContext);
-        jexlUtil.addDerAttrsToContext(attributable.getDerAttrs(), attributable.getAttrs(), jexlContext);
-        jexlUtil.addVirAttrsToContext(attributable.getVirAttrs(), jexlContext);
-
-        return Boolean.parseBoolean(jexlUtil.evaluate(mandatoryCondition, jexlContext));
-    }
-
     private boolean evaluateMandatoryCondition(final AttributableUtil attrUtil, final ExternalResource resource,
             final AbstractAttributable attributable, final String intAttrName, final IntMappingType intMappingType) {
 
@@ -259,7 +243,7 @@ public abstract class AbstractAttributab
                 attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION), intAttrName, intMappingType);
         for (Iterator<AbstractMappingItem> itor = mappings.iterator(); itor.hasNext() && !result;) {
             final AbstractMappingItem mapping = itor.next();
-            result |= evaluateMandatoryCondition(mapping.getMandatoryCondition(), attributable);
+            result |= JexlUtil.evaluateMandatoryCondition(mapping.getMandatoryCondition(), attributable);
         }
 
         return result;
@@ -307,9 +291,9 @@ public abstract class AbstractAttributab
         for (AbstractNormalSchema schema : normalSchemas) {
             if (attributable.getAttr(schema.getName()) == null
                     && !schema.isReadonly()
-                    && (evaluateMandatoryCondition(schema.getMandatoryCondition(), attributable)
+                    && (JexlUtil.evaluateMandatoryCondition(schema.getMandatoryCondition(), attributable)
                     || evaluateMandatoryCondition(attrUtil, attributable, schema.getName(),
-                    attrUtil.intMappingType()))) {
+                            attrUtil.intMappingType()))) {
 
                 LOG.error("Mandatory schema " + schema.getName() + " not provided with values");
 
@@ -335,7 +319,7 @@ public abstract class AbstractAttributab
         for (AbstractDerSchema derSchema : derSchemas) {
             if (attributable.getDerAttr(derSchema.getName()) == null
                     && evaluateMandatoryCondition(attrUtil, attributable, derSchema.getName(),
-                    attrUtil.derIntMappingType())) {
+                            attrUtil.derIntMappingType())) {
 
                 LOG.error("Mandatory derived schema " + derSchema.getName() + " does not evaluate to any value");
 
@@ -362,7 +346,7 @@ public abstract class AbstractAttributab
             if (attributable.getVirAttr(virSchema.getName()) == null
                     && !virSchema.isReadonly()
                     && evaluateMandatoryCondition(attrUtil, attributable, virSchema.getName(),
-                    attrUtil.virIntMappingType())) {
+                            attrUtil.virIntMappingType())) {
 
                 LOG.error("Mandatory virtual schema " + virSchema.getName() + " not provided with values");
 
@@ -622,7 +606,6 @@ public abstract class AbstractAttributab
                     }
                 }
 
-
                 // 1.1 remove values
                 Set<Long> valuesToBeRemoved = new HashSet<Long>();
                 for (String valueToBeRemoved : attributeMod.getValuesToBeRemoved()) {

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/ResourceDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/ResourceDataBinder.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/ResourceDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/ResourceDataBinder.java Tue Nov 12 08:55:31 2013
@@ -63,15 +63,12 @@ public class ResourceDataBinder {
      */
     private static final Logger LOG = LoggerFactory.getLogger(ResourceDataBinder.class);
 
-    private static final String[] MAPPINGITEM_IGNORE_PROPERTIES = {"id", "mapping"};
+    private static final String[] MAPPINGITEM_IGNORE_PROPERTIES = { "id", "mapping" };
 
     @Autowired
     private ConnInstanceDAO connInstanceDAO;
 
     @Autowired
-    private JexlUtil jexlUtil;
-
-    @Autowired
     private PolicyDAO policyDAO;
 
     public ExternalResource create(final ResourceTO resourceTO) {
@@ -203,7 +200,7 @@ public class ResourceDataBinder {
         }
 
         // no mandatory condition implies mandatory condition false
-        if (!jexlUtil.isExpressionValid(itemTO.getMandatoryCondition() == null
+        if (!JexlUtil.isExpressionValid(itemTO.getMandatoryCondition() == null
                 ? "false" : itemTO.getMandatoryCondition())) {
 
             SyncopeClientException invalidMandatoryCondition = SyncopeClientException.build(

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/SchemaDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/SchemaDataBinder.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/SchemaDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/SchemaDataBinder.java Tue Nov 12 08:55:31 2013
@@ -43,12 +43,9 @@ public class SchemaDataBinder {
     @Autowired
     private SchemaDAO schemaDAO;
 
-    @Autowired
-    private JexlUtil jexlUtil;
-
     // --------------- NORMAL -----------------
     private <T extends AbstractNormalSchema> void fill(final T schema, final SchemaTO schemaTO) {
-        if (!jexlUtil.isExpressionValid(schemaTO.getMandatoryCondition())) {
+        if (!JexlUtil.isExpressionValid(schemaTO.getMandatoryCondition())) {
             SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidValues);
             sce.getElements().add(schemaTO.getMandatoryCondition());
             throw sce;
@@ -108,7 +105,7 @@ public class SchemaDataBinder {
             requiredValuesMissing.getElements().add("expression");
 
             scce.addException(requiredValuesMissing);
-        } else if (!jexlUtil.isExpressionValid(derSchemaTO.getExpression())) {
+        } else if (!JexlUtil.isExpressionValid(derSchemaTO.getExpression())) {
             SyncopeClientException invalidMandatoryCondition = SyncopeClientException.build(
                     ClientExceptionType.InvalidValues);
             invalidMandatoryCondition.getElements().add(derSchemaTO.getExpression());

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/TaskDataBinder.java Tue Nov 12 08:55:31 2013
@@ -64,9 +64,9 @@ public class TaskDataBinder {
      */
     private static final Logger LOG = LoggerFactory.getLogger(TaskDataBinder.class);
 
-    private static final String[] IGNORE_TASK_PROPERTIES = {"executions", "resource",};
+    private static final String[] IGNORE_TASK_PROPERTIES = { "executions", "resource", };
 
-    private static final String[] IGNORE_TASK_EXECUTION_PROPERTIES = {"id", "task"};
+    private static final String[] IGNORE_TASK_EXECUTION_PROPERTIES = { "id", "task" };
 
     @Autowired
     private ResourceDAO resourceDAO;
@@ -77,17 +77,14 @@ public class TaskDataBinder {
     @Autowired
     private SchedulerFactoryBean scheduler;
 
-    @Autowired
-    private JexlUtil jexlUtil;
-
     private void checkJexl(final AbstractAttributableTO attributableTO, final SyncopeClientException sce) {
         for (AttributeTO attrTO : attributableTO.getAttrs()) {
-            if (!attrTO.getValues().isEmpty() && !jexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
+            if (!attrTO.getValues().isEmpty() && !JexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
                 sce.getElements().add("Invalid JEXL: " + attrTO.getValues().get(0));
             }
         }
         for (AttributeTO attrTO : attributableTO.getVirAttrs()) {
-            if (!attrTO.getValues().isEmpty() && !jexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
+            if (!attrTO.getValues().isEmpty() && !JexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
                 sce.getElements().add("Invalid JEXL: " + attrTO.getValues().get(0));
             }
         }
@@ -100,10 +97,10 @@ public class TaskDataBinder {
         if (taskTO.getUserTemplate() != null) {
             UserTO template = taskTO.getUserTemplate();
 
-            if (StringUtils.isNotBlank(template.getUsername()) && !jexlUtil.isExpressionValid(template.getUsername())) {
+            if (StringUtils.isNotBlank(template.getUsername()) && !JexlUtil.isExpressionValid(template.getUsername())) {
                 sce.getElements().add("Invalid JEXL: " + template.getUsername());
             }
-            if (StringUtils.isNotBlank(template.getPassword()) && !jexlUtil.isExpressionValid(template.getPassword())) {
+            if (StringUtils.isNotBlank(template.getPassword()) && !JexlUtil.isExpressionValid(template.getPassword())) {
                 sce.getElements().add("Invalid JEXL: " + template.getPassword());
             }
 
@@ -116,7 +113,7 @@ public class TaskDataBinder {
         if (taskTO.getRoleTemplate() != null) {
             RoleTO template = taskTO.getRoleTemplate();
 
-            if (StringUtils.isNotBlank(template.getName()) && !jexlUtil.isExpressionValid(template.getName())) {
+            if (StringUtils.isNotBlank(template.getName()) && !JexlUtil.isExpressionValid(template.getName())) {
                 sce.getElements().add("Invalid JEXL: " + template.getName());
             }
 

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/data/UserDataBinder.java Tue Nov 12 08:55:31 2013
@@ -304,7 +304,6 @@ public class UserDataBinder extends Abst
             if (membership == null) {
                 LOG.debug("Invalid membership id specified to be removed: {}", membershipId);
             } else {
-
                 if (!membershipToBeAddedRoleIds.contains(membership.getSyncopeRole().getId())) {
                     toBeDeprovisioned.addAll(membership.getSyncopeRole().getResourceNames());
                 }
@@ -315,7 +314,6 @@ public class UserDataBinder extends Abst
                 // some modifications compared to the one stored in the DB
                 membership = user.getMembership(membership.getSyncopeRole().getId());
                 if (membershipToBeAddedRoleIds.contains(membership.getSyncopeRole().getId())) {
-
                     Set<Long> attributeIds = new HashSet<Long>(membership.getAttrs().size());
                     for (AbstractAttr attribute : membership.getAttrs()) {
                         attributeIds.add(attribute.getId());
@@ -327,7 +325,6 @@ public class UserDataBinder extends Abst
 
                     // remove derived attributes
                     for (AbstractDerAttr derAttr : membership.getDerAttrs()) {
-
                         attributeIds.add(derAttr.getId());
                     }
                     for (Long derAttrId : attributeIds) {

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/AttributableUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/AttributableUtil.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/util/AttributableUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/AttributableUtil.java Tue Nov 12 08:55:31 2013
@@ -240,6 +240,7 @@ public final class AttributableUtil {
                     }
                 }
                 break;
+
             case PROPAGATION:
                 for (T item : items) {
                     if (MappingPurpose.SYNCHRONIZATION != item.getPurpose()) {
@@ -247,7 +248,9 @@ public final class AttributableUtil {
                     }
                 }
                 break;
+
             case BOTH:
+            default:
                 result.addAll(items);
         }
 

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/JexlUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/JexlUtil.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/util/JexlUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/JexlUtil.java Tue Nov 12 08:55:31 2013
@@ -37,16 +37,16 @@ import org.apache.commons.lang3.StringUt
 import org.apache.syncope.common.to.AbstractAttributableTO;
 import org.apache.syncope.common.to.AttributeTO;
 import org.apache.syncope.core.persistence.beans.AbstractAttr;
+import org.apache.syncope.core.persistence.beans.AbstractAttributable;
 import org.apache.syncope.core.persistence.beans.AbstractDerAttr;
 import org.apache.syncope.core.persistence.beans.AbstractVirAttr;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * @see http://commons.apache.org/jexl/reference/index.html
  */
-public class JexlUtil {
+public final class JexlUtil {
 
     /**
      * Logger.
@@ -54,15 +54,24 @@ public class JexlUtil {
      */
     private static final Logger LOG = LoggerFactory.getLogger(JexlUtil.class);
 
-    private static final String[] IGNORE_FIELDS = {"password", "clearPassword", "serialVersionUID", "class"};
+    private static final String[] IGNORE_FIELDS = { "password", "clearPassword", "serialVersionUID", "class" };
 
-    @Autowired
-    private JexlEngine jexlEngine;
+    private static JexlEngine jexlEngine;
 
-    public boolean isExpressionValid(final String expression) {
+    private static JexlEngine getEngine() {
+        synchronized (LOG) {
+            if (jexlEngine == null) {
+                jexlEngine = ApplicationContextProvider.getApplicationContext().getBean(JexlEngine.class);
+            }
+        }
+
+        return jexlEngine;
+    }
+
+    public static boolean isExpressionValid(final String expression) {
         boolean result;
         try {
-            jexlEngine.createExpression(expression);
+            getEngine().createExpression(expression);
             result = true;
         } catch (JexlException e) {
             LOG.error("Invalid jexl expression: " + expression, e);
@@ -72,12 +81,12 @@ public class JexlUtil {
         return result;
     }
 
-    public String evaluate(final String expression, final JexlContext jexlContext) {
+    public static String evaluate(final String expression, final JexlContext jexlContext) {
         String result = "";
 
         if (StringUtils.isNotBlank(expression) && jexlContext != null) {
             try {
-                Expression jexlExpression = jexlEngine.createExpression(expression);
+                Expression jexlExpression = getEngine().createExpression(expression);
                 Object evaluated = jexlExpression.evaluate(jexlContext);
                 if (evaluated != null) {
                     result = evaluated.toString();
@@ -92,7 +101,7 @@ public class JexlUtil {
         return result;
     }
 
-    public JexlContext addFieldsToContext(final Object attributable, final JexlContext jexlContext) {
+    public static JexlContext addFieldsToContext(final Object attributable, final JexlContext jexlContext) {
         JexlContext context = jexlContext == null ? new MapContext() : jexlContext;
 
         try {
@@ -137,7 +146,7 @@ public class JexlUtil {
         return context;
     }
 
-    public JexlContext addAttrsToContext(final Collection<? extends AbstractAttr> attrs,
+    public static JexlContext addAttrsToContext(final Collection<? extends AbstractAttr> attrs,
             final JexlContext jexlContext) {
 
         JexlContext context = jexlContext == null
@@ -160,7 +169,7 @@ public class JexlUtil {
         return context;
     }
 
-    public JexlContext addDerAttrsToContext(final Collection<? extends AbstractDerAttr> derAttrs,
+    public static JexlContext addDerAttrsToContext(final Collection<? extends AbstractDerAttr> derAttrs,
             final Collection<? extends AbstractAttr> attrs, final JexlContext jexlContext) {
 
         JexlContext context = jexlContext == null
@@ -183,7 +192,7 @@ public class JexlUtil {
         return context;
     }
 
-    public JexlContext addVirAttrsToContext(final Collection<? extends AbstractVirAttr> virAttrs,
+    public static JexlContext addVirAttrsToContext(final Collection<? extends AbstractVirAttr> virAttrs,
             final JexlContext jexlContext) {
 
         JexlContext context = jexlContext == null
@@ -206,7 +215,7 @@ public class JexlUtil {
         return context;
     }
 
-    public String evaluate(final String expression, final AbstractAttributableTO attributableTO) {
+    public static String evaluate(final String expression, final AbstractAttributableTO attributableTO) {
         final JexlContext context = new MapContext();
 
         addFieldsToContext(attributableTO, context);
@@ -245,4 +254,22 @@ public class JexlUtil {
         // Evaluate expression using the context prepared before
         return evaluate(expression, context);
     }
+
+    public static boolean evaluateMandatoryCondition(final String mandatoryCondition,
+            final AbstractAttributable attributable) {
+
+        JexlContext jexlContext = new MapContext();
+        addAttrsToContext(attributable.getAttrs(), jexlContext);
+        addDerAttrsToContext(attributable.getDerAttrs(), attributable.getAttrs(), jexlContext);
+        addVirAttrsToContext(attributable.getVirAttrs(), jexlContext);
+
+        return Boolean.parseBoolean(evaluate(mandatoryCondition, jexlContext));
+    }
+
+    /**
+     * Private default constructor, for static-only classes.
+     */
+    private JexlUtil() {
+    }
+
 }

Modified: syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java (original)
+++ syncope/trunk/core/src/main/java/org/apache/syncope/core/util/MappingUtil.java Tue Nov 12 08:55:31 2013
@@ -124,7 +124,6 @@ public final class MappingUtil {
      * @param vAttrsToBeRemoved virtual attributes to be removed
      * @param vAttrsToBeUpdated virtual attributes to be added
      * @return account link + prepared attribute
-     * @throws ClassNotFoundException if schema type for given mapping does not exists in current class loader
      */
     @SuppressWarnings("unchecked")
     public static <T extends AbstractAttributable> Map.Entry<String, Attribute> prepareAttribute(
@@ -266,14 +265,11 @@ public final class MappingUtil {
         // Evaluate AccountLink expression
         String evalAccountLink = null;
         if (StringUtils.isNotBlank(attrUtil.getAccountLink(resource))) {
-            final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
-            final JexlUtil jexlUtil = context.getBean(JexlUtil.class);
-
             final JexlContext jexlContext = new MapContext();
-            jexlUtil.addFieldsToContext(subject, jexlContext);
-            jexlUtil.addAttrsToContext(subject.getAttrs(), jexlContext);
-            jexlUtil.addDerAttrsToContext(subject.getDerAttrs(), subject.getAttrs(), jexlContext);
-            evalAccountLink = jexlUtil.evaluate(attrUtil.getAccountLink(resource), jexlContext);
+            JexlUtil.addFieldsToContext(subject, jexlContext);
+            JexlUtil.addAttrsToContext(subject.getAttrs(), jexlContext);
+            JexlUtil.addDerAttrsToContext(subject.getDerAttrs(), subject.getAttrs(), jexlContext);
+            evalAccountLink = JexlUtil.evaluate(attrUtil.getAccountLink(resource), jexlContext);
         }
 
         // If AccountLink evaluates to an empty string, just use the provided AccountId as Name(),

Modified: syncope/trunk/core/src/main/resources/syncopeContext.xml
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/main/resources/syncopeContext.xml?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/main/resources/syncopeContext.xml (original)
+++ syncope/trunk/core/src/main/resources/syncopeContext.xml Tue Nov 12 08:55:31 2013
@@ -96,8 +96,6 @@ under the License.
     <property name="silent" value="false"/>
   </bean>
   
-  <bean id="jexlUtil" class="org.apache.syncope.core.util.JexlUtil"/>
-  
   <bean id="virAttrCache" class="org.apache.syncope.core.util.VirAttrCache" scope="singleton">
     <constructor-arg value="60"/>
     <constructor-arg value="5000"/>

Modified: syncope/trunk/core/src/test/java/org/apache/syncope/core/notification/NotificationTest.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/test/java/org/apache/syncope/core/notification/NotificationTest.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/test/java/org/apache/syncope/core/notification/NotificationTest.java (original)
+++ syncope/trunk/core/src/test/java/org/apache/syncope/core/notification/NotificationTest.java Tue Nov 12 08:55:31 2013
@@ -33,7 +33,7 @@ import javax.mail.Folder;
 import javax.mail.Message;
 import javax.mail.Session;
 import javax.mail.Store;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.search.MembershipCond;
 import org.apache.syncope.common.search.NodeCond;
 import org.apache.syncope.common.to.MembershipTO;

Modified: syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java
URL: http://svn.apache.org/viewvc/syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java?rev=1540975&r1=1540974&r2=1540975&view=diff
==============================================================================
--- syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java (original)
+++ syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java Tue Nov 12 08:55:31 2013
@@ -34,6 +34,7 @@ import java.util.Date;
 import java.util.List;
 
 import javax.ws.rs.core.Response;
+import org.apache.commons.lang3.SerializationUtils;
 
 import org.apache.syncope.common.mod.AttributeMod;
 import org.apache.syncope.common.mod.MembershipMod;
@@ -49,6 +50,7 @@ import org.apache.syncope.common.to.Bulk
 import org.apache.syncope.common.to.ConfigurationTO;
 import org.apache.syncope.common.to.ConnObjectTO;
 import org.apache.syncope.common.to.MappingItemTO;
+import org.apache.syncope.common.to.MappingTO;
 import org.apache.syncope.common.to.MembershipTO;
 import org.apache.syncope.common.to.PasswordPolicyTO;
 import org.apache.syncope.common.to.PropagationStatusTO;
@@ -1990,7 +1992,7 @@ public class UserTestITCase extends Abst
 
     @Test
     public void issueSYNCOPE383() {
-        // 1. create user on testdb and testdb2
+        // 1. create user without resources
         UserTO userTO = getUniqueSampleTO("syncope383@apache.org");
         userTO.getResources().clear();
         userTO = createUser(userTO);
@@ -2022,6 +2024,8 @@ public class UserTestITCase extends Abst
     public void issueSYNCOPE397() {
         ResourceTO csv = resourceService.read(RESOURCE_NAME_CSV);
         // change mapping of resource-csv
+        MappingTO origMapping = SerializationUtils.clone(csv.getUmapping());
+        assertNotNull(origMapping);
         for (MappingItemTO item : csv.getUmapping().getItems()) {
             if ("email".equals(item.getIntAttrName())) {
                 // unset internal attribute mail and set virtual attribute virtualdata as mapped to external email
@@ -2072,20 +2076,22 @@ public class UserTestITCase extends Abst
         //modify virtual attribute
         userMod.getVirAttrsToRemove().add("virtualdata");
         userMod.getVirAttrsToUpdate().add(attributeMod("virtualdata", "test@testoneone.com"));
-        // check Syncope change password
 
+        // check Syncope change password
         StatusMod pwdPropRequest = new StatusMod();
-        //change pwd on external resource
-        pwdPropRequest.getResourceNames().add("ws-target-resource-2");
-        //change pwd on Syncope
         pwdPropRequest.setOnSyncope(true);
+        pwdPropRequest.getResourceNames().add("ws-target-resource-2");
         userMod.setPwdPropRequest(pwdPropRequest);
+
         toBeUpdated = updateUser(userMod);
         assertNotNull(toBeUpdated);
         assertEquals("test@testoneone.com", toBeUpdated.getVirAttrs().get(0).getValues().get(0));
         // check if propagates correctly with assertEquals on size of tasks list
-
         assertEquals(2, toBeUpdated.getPropagationStatusTOs().size());
+
+        // restore mapping of resource-csv
+        csv.setUmapping(origMapping);
+        resourceService.update(csv.getName(), csv);
     }
 
     @Test
@@ -2252,4 +2258,32 @@ public class UserTestITCase extends Abst
         assertNotNull(userTO);
     }
 
+    @Test
+    public void issueSYNCOPE435() {
+        // 1. try to create user without password - fail
+        UserTO userTO = getUniqueSampleTO("syncope435@syncope.apache.org");
+        userTO.setPassword(null);
+
+        try {
+            createUser(userTO);
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.InvalidSyncopeUser, e.getType());
+        }
+
+        userTO.setPassword("password123");
+        userTO = createUser(userTO);
+        assertNotNull(userTO);
+
+        // 2. try to update user by subscribing a resource - works but propagation is not even attempted
+        UserMod userMod = new UserMod();
+        userMod.getResourcesToAdd().add("ws-target-resource-1");
+
+        userTO = userService.update(userTO.getId(), userMod).readEntity(UserTO.class);
+        assertEquals(Collections.singleton("ws-target-resource-1"), userTO.getResources());
+        assertFalse(userTO.getPropagationStatusTOs().get(0).getStatus().isSuccessful());
+        assertTrue(userTO.getPropagationStatusTOs().get(0).getFailureReason().
+                startsWith("Not attempted because there are mandatory attributes without value(s): [__PASSWORD__]"));
+    }
+
 }