syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ilgro...@apache.org
Subject [40/40] syncope git commit: [SYNCOPE-119] Merge from master
Date Tue, 21 Apr 2015 07:49:55 GMT
[SYNCOPE-119] Merge from master


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

Branch: refs/heads/SYNCOPE-119
Commit: 4115c57b93135ec0881cd99aa317440d0ae3f5c8
Parents: 65d652a bfa7172
Author: Francesco Chicchiriccò <ilgrosso@apache.org>
Authored: Tue Apr 21 09:43:54 2015 +0200
Committer: Francesco Chicchiriccò <ilgrosso@apache.org>
Committed: Tue Apr 21 09:43:54 2015 +0200

----------------------------------------------------------------------
 .../client/lib/RestClientExceptionMapper.java   |  17 +--
 .../client/lib/RestClientFactoryBean.java       |   2 +
 .../syncope/client/lib/SyncopeClient.java       |   2 +-
 .../syncope/client/lib/ConcurrencyTest.java     |   6 +-
 .../apache/syncope/core/logic/UserLogic.java    |   2 +-
 .../syncope/core/misc/ConnObjectUtils.java      |  73 +++++-----
 .../apache/syncope/core/misc/MappingUtils.java  |  13 +-
 .../syncope/core/misc/security/Encryptor.java   |   2 +-
 .../api/entity/AttributableUtils.java           |   2 -
 .../jpa/entity/JPAAttributableUtils.java        |  17 ---
 .../core/persistence/jpa/entity/PolicyTest.java |  14 --
 .../core/persistence/jpa/entity/RealmTest.java  |   8 +-
 .../core/persistence/jpa/entity/UserTest.java   |   2 +-
 core/rest-cxf/pom.xml                           |   6 +-
 .../rest/cxf/RestServiceExceptionMapper.java    |  53 +++++--
 .../src/main/resources/errorMessages.properties |  17 +++
 fit/core-reference/pom.xml                      |   7 +
 .../fit/core/reference/ConnectorITCase.java     |   2 +-
 .../core/reference/ExceptionMapperITCase.java   | 143 +++++++++++++++++++
 .../fit/core/reference/SyncTaskITCase.java      |  10 ++
 pom.xml                                         |   8 +-
 21 files changed, 292 insertions(+), 114 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/4115c57b/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java
----------------------------------------------------------------------
diff --cc client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java
index bb772bc,bcf7d03..d334c30
--- a/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java
+++ b/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java
@@@ -84,9 -85,9 +85,8 @@@ public class RestClientExceptionMapper 
  
          final SyncopeClientCompositeException compException = SyncopeClientException.buildComposite();
  
--        final Set<String> handledExceptions = new HashSet<String>();
-         for (Object exceptionTypeValue : exTypesInHeaders) {
-             final String exTypeAsString = (String) exceptionTypeValue;
 -        for (int i = 0; i < exTypesInHeaders.size(); i++) {
 -            String exTypeAsString = exTypesInHeaders.get(i);
++        Set<String> handledExceptions = new HashSet<>();
++        for (String exTypeAsString : exTypesInHeaders) {
              ClientExceptionType exceptionType = null;
              try {
                  exceptionType = ClientExceptionType.fromHeaderValue(exTypeAsString);

http://git-wip-us.apache.org/repos/asf/syncope/blob/4115c57b/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java
----------------------------------------------------------------------
diff --cc client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java
index ca1c5d2,04b3892..f7a00df
--- a/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java
+++ b/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java
@@@ -62,6 -62,8 +62,8 @@@ public class RestClientFactoryBean exte
          setServiceClass(serviceClass);
          final T serviceInstance = create(serviceClass);
          WebClient.client(serviceInstance).type(mediaType).accept(mediaType);
 -        WebClient.getConfig(WebClient.client(serviceInstance)).getRequestContext().
 -                put("org.apache.cxf.http.header.split", true);
++        WebClient.getConfig(WebClient.client(serviceInstance)).
++                getRequestContext().put("org.apache.cxf.http.header.split", true);
          return serviceInstance;
      }
  }

http://git-wip-us.apache.org/repos/asf/syncope/blob/4115c57b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java
----------------------------------------------------------------------
diff --cc client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java
index c3f4428,2034ce6..c921272
--- a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java
+++ b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java
@@@ -108,28 -90,6 +108,28 @@@ public class SyncopeClient 
          }
      }
  
 +    @SuppressWarnings("unchecked")
 +    public Pair<Map<Entitlement, Set<String>>, UserTO> self() {
 +        Response response = getService(UserSelfService.class).read();
 +        if (response.getStatusInfo().getStatusCode() != Response.Status.OK.getStatusCode()) {
 +            Exception ex = exceptionMapper.fromResponse(response);
 +            if (ex != null) {
 +                throw (RuntimeException) ex;
 +            }
 +        }
 +
 +        try {
 +            return new ImmutablePair<>(
 +                    (Map<Entitlement, Set<String>>) new ObjectMapper().readValue(
-                             response.getHeaderString(RESTHeaders.OWNED_ENTITLEMENTS),
++                            response.getHeaderString(RESTHeaders.OWNED_ENTITLEMENTS).replaceAll("%2C", ","),
 +                            new TypeReference<HashMap<Entitlement, Set<String>>>() {
 +                            }),
 +                    response.readEntity(UserTO.class));
 +        } catch (IOException e) {
 +            throw new IllegalStateException(e);
 +        }
 +    }
 +
      /**
       * Sets the given header on the give service instance.
       *

http://git-wip-us.apache.org/repos/asf/syncope/blob/4115c57b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
----------------------------------------------------------------------
diff --cc core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
index 4929d62,17e577b..10a3650
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/UserLogic.java
@@@ -121,27 -120,31 +121,27 @@@ public class UserLogic extends Abstract
      @PreAuthorize("hasRole('USER_LIST')")
      @Transactional(readOnly = true, rollbackFor = { Throwable.class })
      @Override
 -    public int searchCount(final SearchCond searchCondition) {
 -        return searchDAO.count(RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames()),
 -                searchCondition, SubjectType.USER);
 -    }
 +    public List<UserTO> list(
 +            final int page, final int size, final List<OrderByClause> orderBy, final List<String> realms) {
  
 -    @PreAuthorize("hasRole('USER_LIST')")
 -    @Transactional(readOnly = true, rollbackFor = { Throwable.class })
 -    @Override
 -    public List<UserTO> list(final int page, final int size, final List<OrderByClause> orderBy) {
 -        Set<Long> adminRoleIds = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
 +        return CollectionUtils.collect(userDAO.findAll(
 +                getEffectiveRealms(AuthContextUtils.getAuthorizations().get(Entitlement.USER_LIST), realms),
 +                page, size, orderBy),
 +                new Transformer<User, UserTO>() {
  
 -        List<User> users = userDAO.findAll(adminRoleIds, page, size, orderBy);
 -        List<UserTO> userTOs = new ArrayList<>(users.size());
 -        for (User user : users) {
 -            userTOs.add(binder.getUserTO(user));
 -        }
 -
 -        return userTOs;
 +                    @Override
 +                    public UserTO transform(final User input) {
 +                        return binder.getUserTO(input);
 +                    }
 +                }, new ArrayList<UserTO>());
      }
  
 -    @PreAuthorize("isAuthenticated() "
 -            + "and not(hasRole(T(org.apache.syncope.common.lib.SyncopeConstants).ANONYMOUS_ENTITLEMENT))")
 +    @PreAuthorize("isAuthenticated()")
      @Transactional(readOnly = true)
 -    public UserTO readSelf() {
 -        return binder.getAuthenticatedUserTO();
 +    public Pair<String, UserTO> readSelf() {
 +        return ImmutablePair.of(
-                 POJOHelper.serialize(AuthContextUtils.getAuthorizations()),
++                POJOHelper.serialize(AuthContextUtils.getAuthorizations()).replaceAll(",", "%2C"),
 +                binder.getAuthenticatedUserTO());
      }
  
      @PreAuthorize("hasRole('USER_READ')")

http://git-wip-us.apache.org/repos/asf/syncope/blob/4115c57b/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
----------------------------------------------------------------------
diff --cc core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
index 2b10228,0000000..74c0b41
mode 100644,000000..100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/ConnObjectUtils.java
@@@ -1,746 -1,0 +1,741 @@@
 +/*
 + * 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.misc;
 +
 +import org.apache.syncope.core.misc.policy.InvalidPasswordPolicySpecException;
 +import org.apache.syncope.core.misc.security.PasswordGenerator;
 +import org.apache.syncope.core.misc.security.SecureRandomUtils;
 +import java.util.ArrayList;
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.HashMap;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.syncope.common.lib.AttributableOperations;
 +import org.apache.syncope.common.lib.mod.AbstractAttributableMod;
 +import org.apache.syncope.common.lib.to.AbstractAttributableTO;
 +import org.apache.syncope.common.lib.to.AbstractSubjectTO;
 +import org.apache.syncope.common.lib.to.AttrTO;
 +import org.apache.syncope.common.lib.to.ConnObjectTO;
 +import org.apache.syncope.common.lib.to.MembershipTO;
 +import org.apache.syncope.common.lib.to.GroupTO;
 +import org.apache.syncope.common.lib.to.UserTO;
 +import org.apache.syncope.common.lib.types.AttrSchemaType;
 +import org.apache.syncope.common.lib.types.AttributableType;
 +import org.apache.syncope.common.lib.types.IntMappingType;
 +import org.apache.syncope.common.lib.types.MappingPurpose;
 +import org.apache.syncope.common.lib.types.PasswordPolicySpec;
 +import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 +import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
 +import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 +import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
 +import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 +import org.apache.syncope.core.persistence.api.dao.UserDAO;
 +import org.apache.syncope.core.persistence.api.entity.Attributable;
 +import org.apache.syncope.core.persistence.api.entity.AttributableUtils;
 +import org.apache.syncope.core.persistence.api.entity.ExternalResource;
 +import org.apache.syncope.core.persistence.api.entity.MappingItem;
 +import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 +import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 +import org.apache.syncope.core.persistence.api.entity.Subject;
 +import org.apache.syncope.core.persistence.api.entity.VirAttr;
 +import org.apache.syncope.core.persistence.api.entity.membership.Membership;
 +import org.apache.syncope.core.persistence.api.entity.group.Group;
 +import org.apache.syncope.core.persistence.api.entity.task.SyncTask;
 +import org.apache.syncope.core.persistence.api.entity.user.User;
 +import org.apache.syncope.core.provisioning.api.Connector;
 +import org.apache.syncope.core.provisioning.api.ConnectorFactory;
 +import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
 +import org.apache.syncope.core.provisioning.api.cache.VirAttrCacheValue;
 +import org.apache.syncope.core.misc.security.Encryptor;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.misc.jexl.JexlUtils;
 +import org.apache.syncope.core.persistence.api.dao.RealmDAO;
 +import org.apache.syncope.core.persistence.api.entity.Realm;
 +import org.identityconnectors.common.Base64;
 +import org.identityconnectors.common.security.GuardedByteArray;
 +import org.identityconnectors.common.security.GuardedString;
 +import org.identityconnectors.framework.common.objects.Attribute;
 +import org.identityconnectors.framework.common.objects.ConnectorObject;
 +import org.identityconnectors.framework.common.objects.ObjectClass;
 +import org.identityconnectors.framework.common.objects.OperationOptions;
 +import org.identityconnectors.framework.common.objects.Uid;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.beans.factory.annotation.Autowired;
 +import org.springframework.context.ConfigurableApplicationContext;
 +import org.springframework.stereotype.Component;
 +import org.springframework.transaction.annotation.Transactional;
 +
 +@Component
 +public class ConnObjectUtils {
 +
 +    /**
 +     * Logger.
 +     */
 +    private static final Logger LOG = LoggerFactory.getLogger(ConnObjectUtils.class);
 +
 +    @Autowired
-     private PolicyDAO policyDAO;
- 
-     @Autowired
 +    private RealmDAO realmDAO;
 +
 +    @Autowired
 +    private UserDAO userDAO;
 +
 +    @Autowired
 +    private GroupDAO groupDAO;
 +
 +    @Autowired
 +    private ExternalResourceDAO resourceDAO;
 +
 +    @Autowired
 +    private PlainSchemaDAO plainSchemaDAO;
 +
 +    @Autowired
 +    private PasswordGenerator pwdGen;
 +
 +    private final Encryptor encryptor = Encryptor.getInstance();
 +
 +    /**
 +     * Virtual attribute cache.
 +     */
 +    @Autowired
 +    private VirAttrCache virAttrCache;
 +
 +    public ObjectClass fromSubject(final Subject<?, ?, ?> subject) {
 +        if (subject == null) {
 +            throw new IllegalArgumentException("No ObjectClass could be provided for " + subject);
 +        }
 +
 +        ObjectClass result = null;
 +        if (subject instanceof User) {
 +            result = ObjectClass.ACCOUNT;
 +        }
 +        if (subject instanceof Group) {
 +            result = ObjectClass.GROUP;
 +        }
 +
 +        return result;
 +    }
 +
 +    /**
 +     * Build a UserTO / GroupTO out of connector object attributes and schema mapping.
 +     *
 +     * @param obj connector object
 +     * @param syncTask synchronization task
 +     * @param attrUtils AttributableUtils
 +     * @param <T> user/group
 +     * @return UserTO for the user to be created
 +     */
 +    @Transactional(readOnly = true)
 +    public <T extends AbstractSubjectTO> T getSubjectTO(final ConnectorObject obj, final SyncTask syncTask,
 +            final AttributableUtils attrUtils) {
 +
 +        T subjectTO = getSubjectTOFromConnObject(obj, syncTask, attrUtils);
 +
 +        // (for users) if password was not set above, generate
 +        if (subjectTO instanceof UserTO && StringUtils.isBlank(((UserTO) subjectTO).getPassword())) {
 +            final UserTO userTO = (UserTO) subjectTO;
 +
 +            List<PasswordPolicySpec> ppSpecs = new ArrayList<>();
 +
 +            Realm realm = realmDAO.find(userTO.getRealm());
 +            if (realm != null) {
 +                for (Realm ancestor : realmDAO.findAncestors(realm)) {
 +                    if (ancestor.getPasswordPolicy() != null
 +                            && ancestor.getPasswordPolicy().getSpecification(PasswordPolicySpec.class) != null) {
 +
 +                        ppSpecs.add(ancestor.getPasswordPolicy().getSpecification(PasswordPolicySpec.class));
 +                    }
 +                }
 +            }
 +
 +            for (String resName : userTO.getResources()) {
 +                ExternalResource resource = resourceDAO.find(resName);
 +                if (resource != null && resource.getPasswordPolicy() != null
 +                        && resource.getPasswordPolicy().getSpecification(PasswordPolicySpec.class) != null) {
 +
 +                    ppSpecs.add(resource.getPasswordPolicy().getSpecification(PasswordPolicySpec.class));
 +                }
 +            }
 +
 +            String password;
 +            try {
 +                password = pwdGen.generate(ppSpecs);
 +            } catch (InvalidPasswordPolicySpecException e) {
 +                LOG.error("Could not generate policy-compliant random password for {}", userTO, e);
 +
 +                password = SecureRandomUtils.generateRandomPassword(16);
 +            }
 +            userTO.setPassword(password);
 +        }
 +
 +        return subjectTO;
 +    }
 +
 +    /**
 +     * Build an UserMod out of connector object attributes and schema mapping.
 +     *
 +     * @param key user to be updated
 +     * @param obj connector object
 +     * @param original subject to get diff from
 +     * @param syncTask synchronization task
 +     * @param attrUtils AttributableUtil
 +     * @param <T> user/group
 +     * @return modifications for the user/group to be updated
 +     */
 +    @SuppressWarnings("unchecked")
 +    @Transactional(readOnly = true)
 +    public <T extends AbstractAttributableMod> T getAttributableMod(final Long key, final ConnectorObject obj,
 +            final AbstractAttributableTO original, final SyncTask syncTask, final AttributableUtils attrUtils) {
 +
 +        final AbstractAttributableTO updated = getSubjectTOFromConnObject(obj, syncTask, attrUtils);
 +        updated.setKey(key);
 +
 +        if (AttributableType.USER == attrUtils.getType()) {
 +            // update password if and only if password is really changed
 +            final User user = userDAO.authFetch(key);
 +            if (StringUtils.isBlank(((UserTO) updated).getPassword())
 +                    || encryptor.verify(((UserTO) updated).getPassword(),
 +                            user.getCipherAlgorithm(), user.getPassword())) {
 +
 +                ((UserTO) updated).setPassword(null);
 +            }
 +
 +            for (MembershipTO membTO : ((UserTO) updated).getMemberships()) {
 +                Membership memb = user.getMembership(membTO.getGroupKey());
 +                if (memb != null) {
 +                    membTO.setKey(memb.getKey());
 +                }
 +            }
 +
 +            return (T) AttributableOperations.diff(((UserTO) updated), ((UserTO) original), true);
 +        }
 +        if (AttributableType.GROUP == attrUtils.getType()) {
 +            return (T) AttributableOperations.diff(((GroupTO) updated), ((GroupTO) original), true);
 +        }
 +
 +        return null;
 +    }
 +
 +    private <T extends AbstractSubjectTO> T getSubjectTOFromConnObject(final ConnectorObject obj,
 +            final SyncTask syncTask, final AttributableUtils attrUtils) {
 +
 +        final T subjectTO = attrUtils.newSubjectTO();
 +
 +        // 1. fill with data from connector object
 +        subjectTO.setRealm(syncTask.getDestinatioRealm().getFullPath());
-         for (MappingItem item : attrUtils.getUidToMappingItems(
-                 syncTask.getResource(), MappingPurpose.SYNCHRONIZATION)) {
- 
-             Attribute attribute = obj.getAttributeByName(item.getExtAttrName());
++        for (MappingItem item : attrUtils.getMappingItems(syncTask.getResource(), MappingPurpose.SYNCHRONIZATION)) {
++            Attribute attr = obj.getAttributeByName(item.getExtAttrName());
 +
-             AttrTO attributeTO;
++            AttrTO attrTO;
 +            switch (item.getIntMappingType()) {
 +                case UserId:
 +                case GroupId:
 +                    break;
 +
 +                case Password:
-                     if (subjectTO instanceof UserTO && attribute != null && attribute.getValue() != null
-                             && !attribute.getValue().isEmpty()) {
++                    if (subjectTO instanceof UserTO && attr != null && attr.getValue() != null
++                            && !attr.getValue().isEmpty()) {
 +
-                         ((UserTO) subjectTO).setPassword(getPassword(attribute.getValue().get(0)));
++                        ((UserTO) subjectTO).setPassword(getPassword(attr.getValue().get(0)));
 +                    }
 +                    break;
 +
 +                case Username:
 +                    if (subjectTO instanceof UserTO) {
-                         ((UserTO) subjectTO).setUsername(attribute == null || attribute.getValue().isEmpty()
-                                 || attribute.getValue().get(0) == null
++                        ((UserTO) subjectTO).setUsername(attr == null || attr.getValue().isEmpty()
++                                || attr.getValue().get(0) == null
 +                                        ? null
-                                         : attribute.getValue().get(0).toString());
++                                        : attr.getValue().get(0).toString());
 +                    }
 +                    break;
 +
 +                case GroupName:
 +                    if (subjectTO instanceof GroupTO) {
-                         ((GroupTO) subjectTO).setName(attribute == null || attribute.getValue().isEmpty()
-                                 || attribute.getValue().get(0) == null
++                        ((GroupTO) subjectTO).setName(attr == null || attr.getValue().isEmpty()
++                                || attr.getValue().get(0) == null
 +                                        ? null
-                                         : attribute.getValue().get(0).toString());
++                                        : attr.getValue().get(0).toString());
 +                    }
 +                    break;
 +
 +                case GroupOwnerSchema:
-                     if (subjectTO instanceof GroupTO && attribute != null) {
++                    if (subjectTO instanceof GroupTO && attr != null) {
 +                        // using a special attribute (with schema "", that will be ignored) for carrying the
 +                        // GroupOwnerSchema value
-                         attributeTO = new AttrTO();
-                         attributeTO.setSchema(StringUtils.EMPTY);
-                         if (attribute.getValue().isEmpty() || attribute.getValue().get(0) == null) {
-                             attributeTO.getValues().add(StringUtils.EMPTY);
++                        attrTO = new AttrTO();
++                        attrTO.setSchema(StringUtils.EMPTY);
++                        if (attr.getValue().isEmpty() || attr.getValue().get(0) == null) {
++                            attrTO.getValues().add(StringUtils.EMPTY);
 +                        } else {
-                             attributeTO.getValues().add(attribute.getValue().get(0).toString());
++                            attrTO.getValues().add(attr.getValue().get(0).toString());
 +                        }
 +
-                         ((GroupTO) subjectTO).getPlainAttrs().add(attributeTO);
++                        ((GroupTO) subjectTO).getPlainAttrs().add(attrTO);
 +                    }
 +                    break;
 +
 +                case UserPlainSchema:
 +                case GroupPlainSchema:
-                     attributeTO = new AttrTO();
-                     attributeTO.setSchema(item.getIntAttrName());
++                    attrTO = new AttrTO();
++                    attrTO.setSchema(item.getIntAttrName());
 +
 +                    PlainSchema schema = plainSchemaDAO.find(item.getIntAttrName(), attrUtils.plainSchemaClass());
 +
-                     for (Object value : attribute == null || attribute.getValue() == null
++                    for (Object value : attr == null || attr.getValue() == null
 +                            ? Collections.emptyList()
-                             : attribute.getValue()) {
++                            : attr.getValue()) {
 +
 +                        AttrSchemaType schemaType = schema == null ? AttrSchemaType.String : schema.getType();
 +                        if (value != null) {
 +                            final PlainAttrValue attrValue = attrUtils.newPlainAttrValue();
 +                            switch (schemaType) {
 +                                case String:
 +                                    attrValue.setStringValue(value.toString());
 +                                    break;
 +
 +                                case Binary:
 +                                    attrValue.setBinaryValue((byte[]) value);
 +                                    break;
 +
 +                                default:
 +                                    try {
 +                                        attrValue.parseValue(schema, value.toString());
 +                                    } catch (ParsingValidationException e) {
 +                                        LOG.error("While parsing provided value {}", value, e);
 +                                        attrValue.setStringValue(value.toString());
 +                                        schemaType = AttrSchemaType.String;
 +                                    }
 +                                    break;
 +                            }
-                             attributeTO.getValues().add(attrValue.getValueAsString(schemaType));
++                            attrTO.getValues().add(attrValue.getValueAsString(schemaType));
 +                        }
 +                    }
 +
-                     subjectTO.getPlainAttrs().add(attributeTO);
++                    subjectTO.getPlainAttrs().add(attrTO);
 +                    break;
 +
 +                case UserDerivedSchema:
 +                case GroupDerivedSchema:
-                     attributeTO = new AttrTO();
-                     attributeTO.setSchema(item.getIntAttrName());
-                     subjectTO.getDerAttrs().add(attributeTO);
++                    attrTO = new AttrTO();
++                    attrTO.setSchema(item.getIntAttrName());
++                    subjectTO.getDerAttrs().add(attrTO);
 +                    break;
 +
 +                case UserVirtualSchema:
 +                case GroupVirtualSchema:
-                     attributeTO = new AttrTO();
-                     attributeTO.setSchema(item.getIntAttrName());
++                    attrTO = new AttrTO();
++                    attrTO.setSchema(item.getIntAttrName());
 +
-                     for (Object value : attribute == null || attribute.getValue() == null
++                    for (Object value : attr == null || attr.getValue() == null
 +                            ? Collections.emptyList()
-                             : attribute.getValue()) {
++                            : attr.getValue()) {
 +
 +                        if (value != null) {
-                             attributeTO.getValues().add(value.toString());
++                            attrTO.getValues().add(value.toString());
 +                        }
 +                    }
 +
-                     subjectTO.getVirAttrs().add(attributeTO);
++                    subjectTO.getVirAttrs().add(attrTO);
 +                    break;
 +
 +                default:
 +            }
 +        }
 +
 +        // 2. add data from defined template (if any)
 +        AbstractSubjectTO template = AttributableType.USER == attrUtils.getType()
 +                ? syncTask.getUserTemplate() : syncTask.getGroupTemplate();
 +
 +        if (template != null) {
 +            if (template.getRealm() != null) {
 +                subjectTO.setRealm(template.getRealm());
 +            }
 +
 +            if (template instanceof UserTO) {
 +                if (StringUtils.isNotBlank(((UserTO) template).getUsername())) {
 +                    String evaluated = JexlUtils.evaluate(((UserTO) template).getUsername(), subjectTO);
 +                    if (StringUtils.isNotBlank(evaluated)) {
 +                        ((UserTO) subjectTO).setUsername(evaluated);
 +                    }
 +                }
 +
 +                if (StringUtils.isNotBlank(((UserTO) template).getPassword())) {
 +                    String evaluated = JexlUtils.evaluate(((UserTO) template).getPassword(), subjectTO);
 +                    if (StringUtils.isNotBlank(evaluated)) {
 +                        ((UserTO) subjectTO).setPassword(evaluated);
 +                    }
 +                }
 +
 +                Map<Long, MembershipTO> currentMembs = ((UserTO) subjectTO).getMembershipMap();
 +                for (MembershipTO membTO : ((UserTO) template).getMemberships()) {
 +                    MembershipTO membTBU;
 +                    if (currentMembs.containsKey(membTO.getGroupKey())) {
 +                        membTBU = currentMembs.get(membTO.getGroupKey());
 +                    } else {
 +                        membTBU = new MembershipTO();
 +                        membTBU.setGroupKey(membTO.getGroupKey());
 +                        ((UserTO) subjectTO).getMemberships().add(membTBU);
 +                    }
 +                    fillFromTemplate(membTBU, membTO);
 +                }
 +            }
 +            if (template instanceof GroupTO) {
 +                if (StringUtils.isNotBlank(((GroupTO) template).getName())) {
 +                    String evaluated = JexlUtils.evaluate(((GroupTO) template).getName(), subjectTO);
 +                    if (StringUtils.isNotBlank(evaluated)) {
 +                        ((GroupTO) subjectTO).setName(evaluated);
 +                    }
 +                }
 +
 +                if (((GroupTO) template).getUserOwner() != null) {
 +                    final User userOwner = userDAO.find(((GroupTO) template).getUserOwner());
 +                    if (userOwner != null) {
 +                        ((GroupTO) subjectTO).setUserOwner(userOwner.getKey());
 +                    }
 +                }
 +                if (((GroupTO) template).getGroupOwner() != null) {
 +                    final Group groupOwner = groupDAO.find(((GroupTO) template).getGroupOwner());
 +                    if (groupOwner != null) {
 +                        ((GroupTO) subjectTO).setGroupOwner(groupOwner.getKey());
 +                    }
 +                }
 +
 +                ((GroupTO) subjectTO).getGPlainAttrTemplates().addAll(((GroupTO) template).getGPlainAttrTemplates());
 +                ((GroupTO) subjectTO).getGDerAttrTemplates().addAll(((GroupTO) template).getGDerAttrTemplates());
 +                ((GroupTO) subjectTO).getGVirAttrTemplates().addAll(((GroupTO) template).getGVirAttrTemplates());
 +                ((GroupTO) subjectTO).getMPlainAttrTemplates().addAll(((GroupTO) template).getMPlainAttrTemplates());
 +                ((GroupTO) subjectTO).getMDerAttrTemplates().addAll(((GroupTO) template).getMDerAttrTemplates());
 +                ((GroupTO) subjectTO).getMVirAttrTemplates().addAll(((GroupTO) template).getMVirAttrTemplates());
 +            }
 +
 +            fillFromTemplate(subjectTO, template);
 +
 +            for (String resource : template.getResources()) {
 +                subjectTO.getResources().add(resource);
 +            }
 +        }
 +
 +        return subjectTO;
 +    }
 +
 +    /**
 +     * Extract password value from passed value (if instance of GuardedString or GuardedByteArray).
 +     *
 +     * @param pwd received from the underlying connector
 +     * @return password value
 +     */
 +    public String getPassword(final Object pwd) {
 +        final StringBuilder result = new StringBuilder();
 +
 +        if (pwd instanceof GuardedString) {
 +            ((GuardedString) pwd).access(new GuardedString.Accessor() {
 +
 +                @Override
 +                public void access(final char[] clearChars) {
 +                    result.append(clearChars);
 +                }
 +            });
 +        } else if (pwd instanceof GuardedByteArray) {
 +            ((GuardedByteArray) pwd).access(new GuardedByteArray.Accessor() {
 +
 +                @Override
 +                public void access(final byte[] clearBytes) {
 +                    result.append(new String(clearBytes));
 +                }
 +            });
 +        } else if (pwd instanceof String) {
 +            result.append((String) pwd);
 +        } else {
 +            result.append(pwd.toString());
 +        }
 +
 +        return result.toString();
 +    }
 +
 +    /**
 +     * Get connector object TO from a connector object.
 +     *
 +     * @param connObject connector object.
 +     * @return connector object TO.
 +     */
 +    public ConnObjectTO getConnObjectTO(final ConnectorObject connObject) {
 +        final ConnObjectTO connObjectTO = new ConnObjectTO();
 +
 +        for (Attribute attr : connObject.getAttributes()) {
 +            AttrTO attrTO = new AttrTO();
 +            attrTO.setSchema(attr.getName());
 +
 +            if (attr.getValue() != null) {
 +                for (Object value : attr.getValue()) {
 +                    if (value != null) {
 +                        if (value instanceof GuardedString || value instanceof GuardedByteArray) {
 +                            attrTO.getValues().add(getPassword(value));
 +                        } else if (value instanceof byte[]) {
 +                            attrTO.getValues().add(Base64.encode((byte[]) value));
 +                        } else {
 +                            attrTO.getValues().add(value.toString());
 +                        }
 +                    }
 +                }
 +            }
 +
 +            connObjectTO.getPlainAttrs().add(attrTO);
 +        }
 +
 +        return connObjectTO;
 +    }
 +
 +    /**
 +     * Query connected external resources for values to populated virtual attributes associated with the given owner.
 +     *
 +     * @param owner user or group
 +     * @param attrUtils attributable util
 +     */
 +    public void retrieveVirAttrValues(final Attributable<?, ?, ?> owner, final AttributableUtils attrUtils) {
 +        final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
 +        final ConnectorFactory connFactory = context.getBean(ConnectorFactory.class);
 +
 +        final IntMappingType type = attrUtils.getType() == AttributableType.USER
 +                ? IntMappingType.UserVirtualSchema : attrUtils.getType() == AttributableType.GROUP
 +                        ? IntMappingType.GroupVirtualSchema : IntMappingType.MembershipVirtualSchema;
 +
 +        final Map<String, ConnectorObject> externalResources = new HashMap<>();
 +
 +        // -----------------------
 +        // Retrieve virtual attribute values if and only if they have not been retrieved yet
 +        // -----------------------
 +        for (VirAttr virAttr : owner.getVirAttrs()) {
 +            // reset value set
 +            if (virAttr.getValues().isEmpty()) {
 +                retrieveVirAttrValue(owner, virAttr, attrUtils, type, externalResources, connFactory);
 +            }
 +        }
 +        // -----------------------
 +    }
 +
 +    private void retrieveVirAttrValue(
 +            final Attributable<?, ?, ?> owner,
 +            final VirAttr virAttr,
 +            final AttributableUtils attrUtils,
 +            final IntMappingType type,
 +            final Map<String, ConnectorObject> externalResources,
 +            final ConnectorFactory connFactory) {
 +
 +        final String schemaName = virAttr.getSchema().getKey();
 +        final VirAttrCacheValue virAttrCacheValue = virAttrCache.get(attrUtils.getType(), owner.getKey(), schemaName);
 +
 +        LOG.debug("Retrieve values for virtual attribute {} ({})", schemaName, type);
 +
 +        if (virAttrCache.isValidEntry(virAttrCacheValue)) {
 +            // cached ...
 +            LOG.debug("Values found in cache {}", virAttrCacheValue);
 +            virAttr.getValues().clear();
 +            virAttr.getValues().addAll(new ArrayList<>(virAttrCacheValue.getValues()));
 +        } else {
 +            // not cached ...
 +            LOG.debug("Need one or more remote connections");
 +
 +            final VirAttrCacheValue toBeCached = new VirAttrCacheValue();
 +
 +            // SYNCOPE-458 if virattr owner is a Membership, owner must become user involved in membership because 
 +            // membership mapping is contained in user mapping
 +            final Subject<?, ?, ?> realOwner = owner instanceof Membership
 +                    ? ((Membership) owner).getUser()
 +                    : (Subject) owner;
 +
 +            final Set<ExternalResource> targetResources = owner instanceof Membership
 +                    ? getTargetResources(virAttr, type, attrUtils, realOwner.getResources())
 +                    : getTargetResources(virAttr, type, attrUtils);
 +
 +            for (ExternalResource resource : targetResources) {
 +                LOG.debug("Search values into {}", resource.getKey());
 +                try {
 +                    List<MappingItem> mappings = attrUtils.getMappingItems(resource, MappingPurpose.BOTH);
 +
 +                    ConnectorObject connectorObject;
 +                    if (externalResources.containsKey(resource.getKey())) {
 +                        connectorObject = externalResources.get(resource.getKey());
 +                    } else {
 +                        LOG.debug("Perform connection to {}", resource.getKey());
 +                        final String accountId = attrUtils.getAccountIdItem(resource) == null
 +                                ? null
 +                                : MappingUtils.getAccountIdValue(
 +                                        realOwner, resource, attrUtils.getAccountIdItem(resource));
 +
 +                        if (StringUtils.isBlank(accountId)) {
 +                            throw new IllegalArgumentException("No AccountId found for " + resource.getKey());
 +                        }
 +
 +                        Connector connector = connFactory.getConnector(resource);
 +
 +                        OperationOptions oo =
 +                                connector.getOperationOptions(MappingUtils.getMatchingMappingItems(mappings, type));
 +
 +                        connectorObject = connector.getObject(fromSubject(realOwner), new Uid(accountId), oo);
 +                        externalResources.put(resource.getKey(), connectorObject);
 +                    }
 +
 +                    if (connectorObject != null) {
 +                        // ask for searched virtual attribute value
 +                        Collection<MappingItem> virAttrMappings =
 +                                MappingUtils.getMatchingMappingItems(mappings, schemaName, type);
 +
 +                        // the same virtual attribute could be mapped with one or more external attribute 
 +                        for (MappingItem mapping : virAttrMappings) {
 +                            final Attribute attribute = connectorObject.getAttributeByName(mapping.getExtAttrName());
 +
 +                            if (attribute != null && attribute.getValue() != null) {
 +                                for (Object obj : attribute.getValue()) {
 +                                    if (obj != null) {
 +                                        virAttr.getValues().add(obj.toString());
 +                                    }
 +                                }
 +                            }
 +                        }
 +
 +                        toBeCached.setResourceValues(resource.getKey(), new HashSet<>(virAttr.getValues()));
 +
 +                        LOG.debug("Retrieved values {}", virAttr.getValues());
 +                    }
 +                } catch (Exception e) {
 +                    LOG.error("Error reading connector object from {}", resource.getKey(), e);
 +
 +                    if (virAttrCacheValue != null) {
 +                        toBeCached.forceExpiring();
 +                        LOG.debug("Search for a cached value (even expired!) ...");
 +                        final Set<String> cachedValues = virAttrCacheValue.getValues(resource.getKey());
 +                        if (cachedValues != null) {
 +                            LOG.debug("Use cached value {}", cachedValues);
 +                            virAttr.getValues().addAll(cachedValues);
 +                            toBeCached.setResourceValues(resource.getKey(), new HashSet<>(cachedValues));
 +                        }
 +                    }
 +                }
 +            }
 +
 +            virAttrCache.put(attrUtils.getType(), owner.getKey(), schemaName, toBeCached);
 +        }
 +    }
 +
 +    private Set<ExternalResource> getTargetResources(
 +            final VirAttr attr, final IntMappingType type, final AttributableUtils attrUtils) {
 +
 +        final Set<ExternalResource> resources = new HashSet<>();
 +
 +        if (attr.getOwner() instanceof Subject) {
 +            for (ExternalResource res : ((Subject<?, ?, ?>) attr.getOwner()).getResources()) {
 +                if (!MappingUtils.getMatchingMappingItems(
 +                        attrUtils.getMappingItems(res, MappingPurpose.BOTH),
 +                        attr.getSchema().getKey(), type).isEmpty()) {
 +
 +                    resources.add(res);
 +                }
 +            }
 +        }
 +
 +        return resources;
 +    }
 +
 +    private Set<ExternalResource> getTargetResources(final VirAttr attr, final IntMappingType type,
 +            final AttributableUtils attrUtils, final Set<? extends ExternalResource> ownerResources) {
 +
 +        final Set<ExternalResource> resources = new HashSet<>();
 +
 +        for (ExternalResource res : ownerResources) {
 +            if (!MappingUtils.getMatchingMappingItems(
 +                    attrUtils.getMappingItems(res, MappingPurpose.BOTH),
 +                    attr.getSchema().getKey(), type).isEmpty()) {
 +
 +                resources.add(res);
 +            }
 +        }
 +
 +        return resources;
 +    }
 +
 +    private void fillFromTemplate(final AbstractAttributableTO attributableTO, final AbstractAttributableTO template) {
 +        Map<String, AttrTO> currentAttrMap = attributableTO.getPlainAttrMap();
 +        for (AttrTO templateAttr : template.getPlainAttrs()) {
 +            if (templateAttr.getValues() != null && !templateAttr.getValues().isEmpty()
 +                    && (!currentAttrMap.containsKey(templateAttr.getSchema())
 +                    || currentAttrMap.get(templateAttr.getSchema()).getValues().isEmpty())) {
 +
 +                attributableTO.getPlainAttrs().add(evaluateAttrTemplate(attributableTO, templateAttr));
 +            }
 +        }
 +
 +        currentAttrMap = attributableTO.getDerAttrMap();
 +        for (AttrTO templateDerAttr : template.getDerAttrs()) {
 +            if (!currentAttrMap.containsKey(templateDerAttr.getSchema())) {
 +                attributableTO.getDerAttrs().add(templateDerAttr);
 +            }
 +        }
 +
 +        currentAttrMap = attributableTO.getVirAttrMap();
 +        for (AttrTO templateVirAttr : template.getVirAttrs()) {
 +            if (templateVirAttr.getValues() != null && !templateVirAttr.getValues().isEmpty()
 +                    && (!currentAttrMap.containsKey(templateVirAttr.getSchema())
 +                    || currentAttrMap.get(templateVirAttr.getSchema()).getValues().isEmpty())) {
 +
 +                attributableTO.getVirAttrs().add(evaluateAttrTemplate(attributableTO, templateVirAttr));
 +            }
 +        }
 +    }
 +
 +    private AttrTO evaluateAttrTemplate(final AbstractAttributableTO attributableTO, final AttrTO template) {
 +        AttrTO result = new AttrTO();
 +        result.setSchema(template.getSchema());
 +
 +        if (template.getValues() != null && !template.getValues().isEmpty()) {
 +            for (String value : template.getValues()) {
 +                String evaluated = JexlUtils.evaluate(value, attributableTO);
 +                if (StringUtils.isNotBlank(evaluated)) {
 +                    result.getValues().add(evaluated);
 +                }
 +            }
 +        }
 +
 +        return result;
 +    }
 +
 +    /**
 +     * Transform a
 +     * <code>Collection</code> of {@link Attribute} instances into a {@link Map}. The key to each element in the map is
 +     * the <i>name</i> of an
 +     * <code>Attribute</code>. The value of each element in the map is the
 +     * <code>Attribute</code> instance with that name. <br/> Different from the original because: <ul> <li>map keys are
 +     * transformed toUpperCase()</li> <li>returned map is mutable</li> </ul>
 +     *
 +     * @param attributes set of attribute to transform to a map.
 +     * @return a map of string and attribute.
 +     *
 +     * @see org.identityconnectors.framework.common.objects.AttributeUtil#toMap(java.util.Collection)
 +     */
 +    public Map<String, Attribute> toMap(final Collection<? extends Attribute> attributes) {
 +        final Map<String, Attribute> map = new HashMap<>();
 +        for (Attribute attr : attributes) {
 +            map.put(attr.getName().toUpperCase(), attr);
 +        }
 +        return map;
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4115c57b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
----------------------------------------------------------------------
diff --cc core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
index db49c0f,0000000..535597a
mode 100644,000000..100644
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/MappingUtils.java
@@@ -1,735 -1,0 +1,732 @@@
 +/*
 + * 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.misc;
 +
 +import org.apache.syncope.core.misc.policy.InvalidPasswordPolicySpecException;
 +import org.apache.syncope.core.misc.security.PasswordGenerator;
 +import java.util.ArrayList;
 +import java.util.Collection;
 +import java.util.Collections;
 +import java.util.HashSet;
 +import java.util.List;
 +import java.util.Map;
 +import java.util.Set;
 +import org.apache.commons.collections4.Predicate;
 +import org.apache.commons.jexl2.JexlContext;
 +import org.apache.commons.jexl2.MapContext;
 +import org.apache.commons.lang3.StringUtils;
 +import org.apache.commons.lang3.tuple.ImmutablePair;
 +import org.apache.commons.lang3.tuple.Pair;
 +import org.apache.syncope.common.lib.CollectionUtils2;
 +import org.apache.syncope.common.lib.mod.AttrMod;
 +import org.apache.syncope.common.lib.types.AttrSchemaType;
 +import org.apache.syncope.common.lib.types.AttributableType;
 +import org.apache.syncope.common.lib.types.IntMappingType;
 +import org.apache.syncope.common.lib.types.MappingPurpose;
 +import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 +import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
 +import org.apache.syncope.core.persistence.api.entity.Attributable;
 +import org.apache.syncope.core.persistence.api.entity.AttributableUtils;
 +import org.apache.syncope.core.persistence.api.entity.AttributableUtilsFactory;
 +import org.apache.syncope.core.persistence.api.entity.DerAttr;
 +import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 +import org.apache.syncope.core.persistence.api.entity.ExternalResource;
 +import org.apache.syncope.core.persistence.api.entity.MappingItem;
 +import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 +import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 +import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 +import org.apache.syncope.core.persistence.api.entity.Subject;
 +import org.apache.syncope.core.persistence.api.entity.VirAttr;
 +import org.apache.syncope.core.persistence.api.entity.VirSchema;
 +import org.apache.syncope.core.persistence.api.entity.membership.MDerSchema;
 +import org.apache.syncope.core.persistence.api.entity.membership.MPlainSchema;
 +import org.apache.syncope.core.persistence.api.entity.membership.MVirSchema;
 +import org.apache.syncope.core.persistence.api.entity.membership.Membership;
 +import org.apache.syncope.core.persistence.api.entity.group.GDerSchema;
 +import org.apache.syncope.core.persistence.api.entity.group.GPlainAttrValue;
 +import org.apache.syncope.core.persistence.api.entity.group.GPlainSchema;
 +import org.apache.syncope.core.persistence.api.entity.group.GVirSchema;
 +import org.apache.syncope.core.persistence.api.entity.group.Group;
 +import org.apache.syncope.core.persistence.api.entity.user.UDerSchema;
 +import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
 +import org.apache.syncope.core.persistence.api.entity.user.UPlainSchema;
 +import org.apache.syncope.core.persistence.api.entity.user.UVirSchema;
 +import org.apache.syncope.core.persistence.api.entity.user.User;
 +import org.apache.syncope.core.provisioning.api.cache.VirAttrCache;
 +import org.apache.syncope.core.misc.security.Encryptor;
 +import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
 +import org.apache.syncope.core.misc.jexl.JexlUtils;
 +import org.identityconnectors.framework.common.FrameworkUtil;
 +import org.identityconnectors.framework.common.objects.Attribute;
 +import org.identityconnectors.framework.common.objects.AttributeBuilder;
 +import org.identityconnectors.framework.common.objects.AttributeUtil;
 +import org.identityconnectors.framework.common.objects.Name;
 +import org.identityconnectors.framework.common.objects.OperationalAttributes;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.springframework.context.ConfigurableApplicationContext;
 +
 +public final class MappingUtils {
 +
-     /**
-      * Logger.
-      */
 +    private static final Logger LOG = LoggerFactory.getLogger(MappingUtils.class);
 +
 +    private static final Encryptor ENCRYPTOR = Encryptor.getInstance();
 +
 +    public static <T extends MappingItem> Collection<T> getMatchingMappingItems(
 +            final Collection<T> items, final IntMappingType type) {
 +
 +        return CollectionUtils2.find(items, new Predicate<T>() {
 +
 +            @Override
 +            public boolean evaluate(final T item) {
 +                return item.getIntMappingType() == type;
 +            }
 +        });
 +    }
 +
 +    public static <T extends MappingItem> Collection<T> getMatchingMappingItems(
 +            final Collection<T> items, final String intAttrName, final IntMappingType type) {
 +
 +        return CollectionUtils2.find(items, new Predicate<T>() {
 +
 +            @Override
 +            public boolean evaluate(final T item) {
 +                return item.getIntMappingType() == type && intAttrName.equals(item.getIntAttrName());
 +            }
 +        });
 +    }
 +
 +    public static <T extends MappingItem> Collection<T> getMatchingMappingItems(
 +            final Collection<T> items, final String intAttrName) {
 +
 +        return CollectionUtils2.find(items, new Predicate<T>() {
 +
 +            @Override
 +            public boolean evaluate(final T item) {
 +                return intAttrName.equals(item.getIntAttrName());
 +            }
 +        });
 +    }
 +
 +    /**
 +     * Prepare attributes for sending to a connector instance.
 +     *
 +     * @param attrUtils user / group
 +     * @param subject given user / group
 +     * @param password clear-text password
 +     * @param changePwd whether password should be included for propagation attributes or not
 +     * @param vAttrsToBeRemoved virtual attributes to be removed
 +     * @param vAttrsToBeUpdated virtual attributes to be added
 +     * @param membVAttrsToBeRemoved membership virtual attributes to be removed
 +     * @param membVAttrsToBeUpdated membership virtual attributes to be added
 +     * @param enable whether user must be enabled or not
 +     * @param resource target resource
 +     * @return account link + prepared attributes
 +     */
 +    public static Pair<String, Set<Attribute>> prepareAttributes(
 +            final AttributableUtils attrUtils, final Subject<?, ?, ?> subject,
 +            final String password,
 +            final boolean changePwd,
 +            final Set<String> vAttrsToBeRemoved,
 +            final Map<String, AttrMod> vAttrsToBeUpdated,
 +            final Set<String> membVAttrsToBeRemoved,
 +            final Map<String, AttrMod> membVAttrsToBeUpdated,
 +            final Boolean enable,
 +            final ExternalResource resource) {
 +
 +        LOG.debug("Preparing resource attributes for {} on resource {} with attributes {}",
 +                subject, resource, subject.getPlainAttrs());
 +
 +        final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
 +        final VirAttrCache virAttrCache = context.getBean(VirAttrCache.class);
 +        final PasswordGenerator passwordGenerator = context.getBean(PasswordGenerator.class);
 +
 +        Set<Attribute> attributes = new HashSet<>();
 +        String accountId = null;
 +
 +        for (MappingItem mapping : attrUtils.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
 +            LOG.debug("Processing schema {}", mapping.getIntAttrName());
 +
 +            try {
 +                if ((attrUtils.getType() == AttributableType.USER
 +                        && mapping.getIntMappingType() == IntMappingType.UserVirtualSchema)
 +                        || (attrUtils.getType() == AttributableType.GROUP
 +                        && mapping.getIntMappingType() == IntMappingType.GroupVirtualSchema)) {
 +
 +                    LOG.debug("Expire entry cache {}-{}", subject.getKey(), mapping.getIntAttrName());
 +                    virAttrCache.expire(attrUtils.getType(), subject.getKey(), mapping.getIntAttrName());
 +                }
 +
 +                // SYNCOPE-458 expire cache also for membership virtual schemas
 +                if (attrUtils.getType() == AttributableType.USER && mapping.getIntMappingType()
 +                        == IntMappingType.MembershipVirtualSchema && (subject instanceof User)) {
 +
 +                    final User user = (User) subject;
 +                    for (Membership membership : user.getMemberships()) {
 +                        LOG.debug("Expire entry cache {}-{} for membership {}", subject.getKey(),
 +                                mapping.getIntAttrName(), membership);
 +                        virAttrCache.expire(AttributableType.MEMBERSHIP, membership.getKey(),
 +                                mapping.getIntAttrName());
 +                    }
 +                }
 +
 +                Pair<String, Attribute> preparedAttr = prepareAttr(
 +                        resource, mapping, subject, password, passwordGenerator, vAttrsToBeRemoved, vAttrsToBeUpdated,
 +                        membVAttrsToBeRemoved, membVAttrsToBeUpdated);
 +
 +                if (preparedAttr != null && preparedAttr.getKey() != null) {
 +                    accountId = preparedAttr.getKey();
 +                }
 +
 +                if (preparedAttr != null && preparedAttr.getValue() != null) {
 +                    Attribute alreadyAdded = AttributeUtil.find(preparedAttr.getValue().getName(), attributes);
 +
 +                    if (alreadyAdded == null) {
 +                        attributes.add(preparedAttr.getValue());
 +                    } else {
 +                        attributes.remove(alreadyAdded);
 +
 +                        Set<Object> values = new HashSet<>(alreadyAdded.getValue());
 +                        values.addAll(preparedAttr.getValue().getValue());
 +
 +                        attributes.add(AttributeBuilder.build(preparedAttr.getValue().getName(), values));
 +                    }
 +                }
 +            } catch (Exception e) {
 +                LOG.debug("Attribute '{}' processing failed", mapping.getIntAttrName(), e);
 +            }
 +        }
 +
 +        final Attribute accountIdExtAttr =
 +                AttributeUtil.find(attrUtils.getAccountIdItem(resource).getExtAttrName(), attributes);
 +        if (accountIdExtAttr != null) {
 +            attributes.remove(accountIdExtAttr);
 +            attributes.add(AttributeBuilder.build(attrUtils.getAccountIdItem(resource).getExtAttrName(), accountId));
 +        }
-         attributes.add(MappingUtils.evaluateNAME(subject, resource, accountId));
++        attributes.add(evaluateNAME(subject, resource, accountId));
 +
 +        if (enable != null) {
 +            attributes.add(AttributeBuilder.buildEnabled(enable));
 +        }
 +        if (!changePwd) {
 +            Attribute pwdAttr = AttributeUtil.find(OperationalAttributes.PASSWORD_NAME, attributes);
 +            if (pwdAttr != null) {
 +                attributes.remove(pwdAttr);
 +            }
 +        }
 +
 +        return new ImmutablePair<>(accountId, attributes);
 +    }
 +
 +    /**
 +     * Prepare an attribute to be sent to a connector instance.
 +     *
 +     * @param resource target resource
 +     * @param mapItem mapping item for the given attribute
 +     * @param subject given user
 +     * @param password clear-text password
 +     * @param passwordGenerator password generator
 +     * @param vAttrsToBeRemoved virtual attributes to be removed
 +     * @param vAttrsToBeUpdated virtual attributes to be added
 +     * @return account link + prepared attribute
 +     */
 +    @SuppressWarnings("unchecked")
 +    private static Pair<String, Attribute> prepareAttr(
 +            final ExternalResource resource, final MappingItem mapItem,
 +            final Subject<?, ?, ?> subject, final String password, final PasswordGenerator passwordGenerator,
 +            final Set<String> vAttrsToBeRemoved, final Map<String, AttrMod> vAttrsToBeUpdated,
 +            final Set<String> membVAttrsToBeRemoved, final Map<String, AttrMod> membVAttrsToBeUpdated) {
 +
 +        List<Attributable<?, ?, ?>> attributables = new ArrayList<>();
 +
 +        ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
 +        AttributableUtilsFactory attrUtilsFactory = context.getBean(AttributableUtilsFactory.class);
 +        ConnObjectUtils connObjectUtils = context.getBean(ConnObjectUtils.class);
 +
 +        switch (mapItem.getIntMappingType().getAttributableType()) {
 +            case USER:
 +                if (subject instanceof User) {
 +                    attributables.add(subject);
 +                }
 +                break;
 +
 +            case GROUP:
 +                if (subject instanceof User) {
 +                    for (Group group : ((User) subject).getGroups()) {
 +                        connObjectUtils.retrieveVirAttrValues(group, attrUtilsFactory.getInstance(group));
 +                        attributables.add(group);
 +                    }
 +                }
 +                if (subject instanceof Group) {
 +                    attributables.add(subject);
 +                }
 +                break;
 +
 +            case MEMBERSHIP:
 +                if (subject instanceof User) {
 +                    attributables.addAll(((User) subject).getMemberships());
 +                }
 +                break;
 +
 +            default:
 +        }
 +
 +        List<PlainAttrValue> values = getIntValues(
 +                resource, mapItem, attributables, vAttrsToBeRemoved, vAttrsToBeUpdated, membVAttrsToBeRemoved,
 +                membVAttrsToBeUpdated);
 +
 +        PlainSchema schema = null;
 +        boolean readOnlyVirSchema = false;
 +        AttrSchemaType schemaType;
 +        final Pair<String, Attribute> result;
 +
 +        switch (mapItem.getIntMappingType()) {
 +            case UserPlainSchema:
 +            case GroupPlainSchema:
 +            case MembershipPlainSchema:
 +                final PlainSchemaDAO plainSchemaDAO = context.getBean(PlainSchemaDAO.class);
-                 schema = plainSchemaDAO.find(mapItem.getIntAttrName(),
-                         MappingUtils.getIntMappingTypeClass(mapItem.getIntMappingType()));
++                schema = plainSchemaDAO.find(
++                        mapItem.getIntAttrName(), getIntMappingTypeClass(mapItem.getIntMappingType()));
 +                schemaType = schema == null ? AttrSchemaType.String : schema.getType();
 +                break;
 +
 +            case UserVirtualSchema:
 +            case GroupVirtualSchema:
 +            case MembershipVirtualSchema:
 +                VirSchemaDAO virSchemaDAO = context.getBean(VirSchemaDAO.class);
-                 VirSchema virSchema = virSchemaDAO.find(mapItem.getIntAttrName(),
-                         MappingUtils.getIntMappingTypeClass(mapItem.getIntMappingType()));
++                VirSchema virSchema = virSchemaDAO.find(
++                        mapItem.getIntAttrName(), getIntMappingTypeClass(mapItem.getIntMappingType()));
 +                readOnlyVirSchema = (virSchema != null && virSchema.isReadonly());
 +                schemaType = AttrSchemaType.String;
 +                break;
 +
 +            default:
 +                schemaType = AttrSchemaType.String;
 +        }
 +
 +        final String extAttrName = mapItem.getExtAttrName();
 +
 +        LOG.debug("Define mapping for: "
 +                + "\n* ExtAttrName " + extAttrName
 +                + "\n* is accountId " + mapItem.isAccountid()
 +                + "\n* is password " + (mapItem.isPassword() || mapItem.getIntMappingType() == IntMappingType.Password)
 +                + "\n* mandatory condition " + mapItem.getMandatoryCondition()
 +                + "\n* Schema " + mapItem.getIntAttrName()
 +                + "\n* IntMappingType " + mapItem.getIntMappingType().toString()
 +                + "\n* ClassType " + schemaType.getType().getName()
 +                + "\n* Values " + values);
 +
 +        if (readOnlyVirSchema) {
 +            result = null;
 +        } else {
 +            final List<Object> objValues = new ArrayList<>();
 +
 +            for (PlainAttrValue value : values) {
 +                if (FrameworkUtil.isSupportedAttributeType(schemaType.getType())) {
 +                    objValues.add(value.getValue());
 +                } else {
 +                    objValues.add(value.getValueAsString());
 +                }
 +            }
 +
 +            if (mapItem.isAccountid()) {
 +                result = new ImmutablePair<>(objValues.iterator().next().toString(), null);
 +            } else if (mapItem.isPassword() && subject instanceof User) {
 +                String passwordAttrValue = password;
 +                if (StringUtils.isBlank(passwordAttrValue)) {
 +                    User user = (User) subject;
 +                    if (user.canDecodePassword()) {
 +                        try {
 +                            passwordAttrValue = ENCRYPTOR.decode(user.getPassword(), user.getCipherAlgorithm());
 +                        } catch (Exception e) {
 +                            LOG.error("Could not decode password for {}", user, e);
 +                        }
 +                    } else if (resource.isRandomPwdIfNotProvided()) {
 +                        try {
 +                            passwordAttrValue = passwordGenerator.generate(user);
 +                        } catch (InvalidPasswordPolicySpecException e) {
 +                            LOG.error("Could not generate policy-compliant random password for {}", user, e);
 +                        }
 +                    }
 +                }
 +
 +                if (passwordAttrValue == null) {
 +                    result = null;
 +                } else {
 +                    result = new ImmutablePair<>(
 +                            null,
 +                            AttributeBuilder.buildPassword(passwordAttrValue.toCharArray()));
 +                }
 +            } else {
 +                if ((schema != null && schema.isMultivalue()) || attrUtilsFactory.getInstance(subject).getType()
 +                        != mapItem.getIntMappingType().getAttributableType()) {
 +
 +                    result = new ImmutablePair<>(
 +                            null,
 +                            AttributeBuilder.build(extAttrName, objValues));
 +                } else {
 +                    result = new ImmutablePair<>(
 +                            null, objValues.isEmpty()
 +                                    ? AttributeBuilder.build(extAttrName)
 +                                    : AttributeBuilder.build(extAttrName, objValues.iterator().next()));
 +                }
 +            }
 +        }
 +
 +        return result;
 +    }
 +
 +    /**
 +     * Build __NAME__ for propagation. First look if there ia a defined accountLink for the given resource (and in this
 +     * case evaluate as JEXL); otherwise, take given accountId.
 +     *
 +     * @param subject given user / group
 +     * @param resource target resource
 +     * @param accountId accountId
 +     * @return the value to be propagated as __NAME__
 +     */
 +    public static Name evaluateNAME(final Subject<?, ?, ?> subject,
 +            final ExternalResource resource, final String accountId) {
 +
 +        final AttributableUtilsFactory attrUtilsFactory =
 +                ApplicationContextProvider.getApplicationContext().getBean(AttributableUtilsFactory.class);
 +        final AttributableUtils attrUtils = attrUtilsFactory.getInstance(subject);
 +
 +        if (StringUtils.isBlank(accountId)) {
 +            // LOG error but avoid to throw exception: leave it to the external resource
 +            LOG.error("Missing accountId for '{}': ", resource.getKey());
 +        }
 +
 +        // Evaluate AccountLink expression
 +        String evalAccountLink = null;
 +        if (StringUtils.isNotBlank(attrUtils.getAccountLink(resource))) {
 +            final JexlContext jexlContext = new MapContext();
 +            JexlUtils.addFieldsToContext(subject, jexlContext);
 +            JexlUtils.addAttrsToContext(subject.getPlainAttrs(), jexlContext);
 +            JexlUtils.addDerAttrsToContext(subject.getDerAttrs(), subject.getPlainAttrs(), jexlContext);
 +            evalAccountLink = JexlUtils.evaluate(attrUtils.getAccountLink(resource), jexlContext);
 +        }
 +
 +        // If AccountLink evaluates to an empty string, just use the provided AccountId as Name(),
 +        // otherwise evaluated AccountLink expression is taken as Name().
 +        Name name;
 +        if (StringUtils.isBlank(evalAccountLink)) {
 +            // add AccountId as __NAME__ attribute ...
 +            LOG.debug("Add AccountId [{}] as __NAME__", accountId);
 +            name = new Name(accountId);
 +        } else {
 +            LOG.debug("Add AccountLink [{}] as __NAME__", evalAccountLink);
 +            name = new Name(evalAccountLink);
 +
 +            // AccountId not propagated: it will be used to set the value for __UID__ attribute
 +            LOG.debug("AccountId will be used just as __UID__ attribute");
 +        }
 +
 +        return name;
 +    }
 +
 +    private static String getGroupOwnerValue(
 +            final ExternalResource resource, final Subject<?, ?, ?> subject) {
 +
 +        AttributableUtilsFactory attrUtilsFactory =
 +                ApplicationContextProvider.getApplicationContext().getBean(AttributableUtilsFactory.class);
 +
 +        Pair<String, Attribute> preparedAttr = prepareAttr(
 +                resource, attrUtilsFactory.getInstance(subject).getAccountIdItem(resource), subject, null, null,
 +                Collections.<String>emptySet(), Collections.<String, AttrMod>emptyMap(),
 +                Collections.<String>emptySet(), Collections.<String, AttrMod>emptyMap());
 +        String accountId = preparedAttr.getKey();
 +
 +        final Name groupOwnerName = evaluateNAME(subject, resource, accountId);
 +        return groupOwnerName.getNameValue();
 +    }
 +
 +    /**
 +     * Get attribute values.
 +     *
 +     * @param resource target resource
 +     * @param mappingItem mapping item
 +     * @param attributables list of attributables
 +     * @param vAttrsToBeRemoved virtual attributes to be removed
 +     * @param vAttrsToBeUpdated virtual attributes to be added
 +     * @param membVAttrsToBeRemoved membership virtual attributes to be removed
 +     * @param membVAttrsToBeUpdated membership virtual attributes to be added
 +     * @return attribute values.
 +     */
 +    public static List<PlainAttrValue> getIntValues(final ExternalResource resource,
 +            final MappingItem mappingItem, final List<Attributable<?, ?, ?>> attributables,
 +            final Set<String> vAttrsToBeRemoved, final Map<String, AttrMod> vAttrsToBeUpdated,
 +            final Set<String> membVAttrsToBeRemoved, final Map<String, AttrMod> membVAttrsToBeUpdated) {
 +
 +        LOG.debug("Get attributes for '{}' and mapping type '{}'", attributables, mappingItem.getIntMappingType());
 +
 +        final EntityFactory entityFactory =
 +                ApplicationContextProvider.getApplicationContext().getBean(EntityFactory.class);
 +        List<PlainAttrValue> values = new ArrayList<>();
 +        PlainAttrValue attrValue;
 +        switch (mappingItem.getIntMappingType()) {
 +            case UserPlainSchema:
 +            case GroupPlainSchema:
 +            case MembershipPlainSchema:
 +                for (Attributable<?, ?, ?> attributable : attributables) {
 +                    final PlainAttr attr = attributable.getPlainAttr(mappingItem.getIntAttrName());
 +                    if (attr != null) {
 +                        if (attr.getUniqueValue() != null) {
 +                            values.add(attr.getUniqueValue());
 +                        } else if (attr.getValues() != null) {
 +                            values.addAll(attr.getValues());
 +                        }
 +                    }
 +
 +                    LOG.debug("Retrieved attribute {}"
 +                            + "\n* IntAttrName {}"
 +                            + "\n* IntMappingType {}"
 +                            + "\n* Attribute values {}",
 +                            attr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
 +                }
 +
 +                break;
 +
 +            case UserVirtualSchema:
 +            case GroupVirtualSchema:
 +                for (Attributable<?, ?, ?> attributable : attributables) {
 +                    VirAttr virAttr = attributable.getVirAttr(mappingItem.getIntAttrName());
 +                    if (virAttr != null) {
 +                        if (vAttrsToBeRemoved != null && vAttrsToBeUpdated != null) {
 +                            if (vAttrsToBeUpdated.containsKey(mappingItem.getIntAttrName())) {
 +                                virAttr.getValues().clear();
 +                                virAttr.getValues().addAll(
 +                                        vAttrsToBeUpdated.get(mappingItem.getIntAttrName()).getValuesToBeAdded());
 +                            } else if (vAttrsToBeRemoved.contains(mappingItem.getIntAttrName())) {
 +                                virAttr.getValues().clear();
 +                            } else {
 +                                throw new IllegalArgumentException("Don't need to update virtual attribute '"
 +                                        + mappingItem.getIntAttrName() + "'");
 +                            }
 +                        }
 +                        if (virAttr.getValues() != null) {
 +                            for (String value : virAttr.getValues()) {
 +                                attrValue = entityFactory.newEntity(UPlainAttrValue.class);
 +                                attrValue.setStringValue(value);
 +                                values.add(attrValue);
 +                            }
 +                        }
 +                    }
 +
 +                    LOG.debug("Retrieved {} virtual attribute {}"
 +                            + "\n* IntAttrName {}"
 +                            + "\n* IntMappingType {}"
 +                            + "\n* Attribute values {}",
 +                            attributable.getClass().getSimpleName(),
 +                            virAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
 +                }
 +                break;
 +
 +            case MembershipVirtualSchema:
 +                for (Attributable<?, ?, ?> attributable : attributables) {
 +                    VirAttr virAttr = attributable.getVirAttr(mappingItem.getIntAttrName());
 +                    if (virAttr != null) {
 +                        if (membVAttrsToBeRemoved != null && membVAttrsToBeUpdated != null) {
 +                            if (membVAttrsToBeUpdated.containsKey(mappingItem.getIntAttrName())) {
 +                                virAttr.getValues().clear();
 +                                virAttr.getValues().addAll(
 +                                        membVAttrsToBeUpdated.get(mappingItem.getIntAttrName()).getValuesToBeAdded());
 +                            } else if (membVAttrsToBeRemoved.contains(mappingItem.getIntAttrName())) {
 +                                virAttr.getValues().clear();
 +                            } else {
 +                                throw new IllegalArgumentException("Don't need to update membership virtual attribute '"
 +                                        + mappingItem.getIntAttrName() + "'");
 +                            }
 +                        }
 +                        if (virAttr.getValues() != null) {
 +                            for (String value : virAttr.getValues()) {
 +                                attrValue = entityFactory.newEntity(UPlainAttrValue.class);
 +                                attrValue.setStringValue(value);
 +                                values.add(attrValue);
 +                            }
 +                        }
 +                    }
 +
 +                    LOG.debug("Retrieved {} virtual attribute {}"
 +                            + "\n* IntAttrName {}"
 +                            + "\n* IntMappingType {}"
 +                            + "\n* Attribute values {}",
 +                            attributable.getClass().getSimpleName(),
 +                            virAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
 +                }
 +                break;
 +
 +            case UserDerivedSchema:
 +            case GroupDerivedSchema:
 +            case MembershipDerivedSchema:
 +                for (Attributable<?, ?, ?> attributable : attributables) {
 +                    DerAttr derAttr = attributable.getDerAttr(mappingItem.getIntAttrName());
 +                    if (derAttr != null) {
 +                        attrValue = attributable instanceof Group
 +                                ? entityFactory.newEntity(GPlainAttrValue.class)
 +                                : entityFactory.newEntity(UPlainAttrValue.class);
 +                        attrValue.setStringValue(derAttr.getValue(attributable.getPlainAttrs()));
 +                        values.add(attrValue);
 +                    }
 +
 +                    LOG.debug("Retrieved attribute {}"
 +                            + "\n* IntAttrName {}"
 +                            + "\n* IntMappingType {}"
 +                            + "\n* Attribute values {}",
 +                            derAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
 +                }
 +                break;
 +
 +            case UserId:
 +            case GroupId:
 +            case MembershipId:
 +                for (Attributable<?, ?, ?> attributable : attributables) {
 +                    attrValue = entityFactory.newEntity(UPlainAttrValue.class);
 +                    attrValue.setStringValue(attributable.getKey().toString());
 +                    values.add(attrValue);
 +                }
 +                break;
 +
 +            case Username:
 +                for (Attributable<?, ?, ?> attributable : attributables) {
 +                    if (attributable instanceof User) {
 +                        attrValue = entityFactory.newEntity(UPlainAttrValue.class);
 +                        attrValue.setStringValue(((User) attributable).getUsername());
 +                        values.add(attrValue);
 +                    }
 +                }
 +                break;
 +
 +            case GroupName:
 +                for (Attributable<?, ?, ?> attributable : attributables) {
 +                    if (attributable instanceof Group) {
 +                        attrValue = entityFactory.newEntity(GPlainAttrValue.class);
 +                        attrValue.setStringValue(((Group) attributable).getName());
 +                        values.add(attrValue);
 +                    }
 +                }
 +                break;
 +
 +            case GroupOwnerSchema:
 +                for (Attributable<?, ?, ?> attributable : attributables) {
 +                    if (attributable instanceof Group) {
 +                        Group group = (Group) attributable;
 +                        String groupOwnerValue = null;
 +                        if (group.getUserOwner() != null && resource.getUmapping() != null) {
 +                            groupOwnerValue = getGroupOwnerValue(resource, group.getUserOwner());
 +                        }
 +                        if (group.getGroupOwner() != null && resource.getGmapping() != null) {
 +                            groupOwnerValue = getGroupOwnerValue(resource, group.getGroupOwner());
 +                        }
 +
 +                        if (StringUtils.isNotBlank(groupOwnerValue)) {
 +                            attrValue = entityFactory.newEntity(GPlainAttrValue.class);
 +                            attrValue.setStringValue(groupOwnerValue);
 +                            values.add(attrValue);
 +                        }
 +                    }
 +                }
 +                break;
 +
 +            default:
 +        }
 +
 +        LOG.debug("Retrieved values '{}'", values);
 +
 +        return values;
 +    }
 +
 +    /**
 +     * Get accountId internal value.
 +     *
 +     * @param attributable attributable
 +     * @param accountIdItem accountId mapping item
 +     * @param resource external resource
 +     * @return accountId internal value
 +     */
 +    public static String getAccountIdValue(final Attributable<?, ?, ?> attributable,
 +            final ExternalResource resource, final MappingItem accountIdItem) {
 +
 +        List<PlainAttrValue> values = getIntValues(resource, accountIdItem,
 +                Collections.<Attributable<?, ?, ?>>singletonList(attributable), null, null, null, null);
 +        return values == null || values.isEmpty()
 +                ? null
 +                : values.get(0).getValueAsString();
 +    }
 +
 +    /**
 +     * For given source mapping type, return the corresponding Class object.
 +     *
 +     * @param intMappingType source mapping type
 +     * @return corresponding Class object, if any (can be null)
 +     */
 +    @SuppressWarnings("rawtypes")
 +    public static Class getIntMappingTypeClass(final IntMappingType intMappingType) {
 +        Class result;
 +
 +        switch (intMappingType) {
 +            case UserPlainSchema:
 +                result = UPlainSchema.class;
 +                break;
 +
 +            case GroupPlainSchema:
 +                result = GPlainSchema.class;
 +                break;
 +
 +            case MembershipPlainSchema:
 +                result = MPlainSchema.class;
 +                break;
 +
 +            case UserDerivedSchema:
 +                result = UDerSchema.class;
 +                break;
 +
 +            case GroupDerivedSchema:
 +                result = GDerSchema.class;
 +                break;
 +
 +            case MembershipDerivedSchema:
 +                result = MDerSchema.class;
 +                break;
 +
 +            case UserVirtualSchema:
 +                result = UVirSchema.class;
 +                break;
 +
 +            case GroupVirtualSchema:
 +                result = GVirSchema.class;
 +                break;
 +
 +            case MembershipVirtualSchema:
 +                result = MVirSchema.class;
 +                break;
 +
 +            default:
 +                result = null;
 +        }
 +
 +        return result;
 +    }
 +
 +    /**
 +     * Private default constructor, for static-only classes.
 +     */
 +    private MappingUtils() {
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/syncope/blob/4115c57b/core/misc/src/main/java/org/apache/syncope/core/misc/security/Encryptor.java
----------------------------------------------------------------------
diff --cc core/misc/src/main/java/org/apache/syncope/core/misc/security/Encryptor.java
index ce3b36c,aac337a..4c55513
--- a/core/misc/src/main/java/org/apache/syncope/core/misc/security/Encryptor.java
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/Encryptor.java
@@@ -46,7 -46,7 +46,7 @@@ public final class Encryptor 
  
      private static final Logger LOG = LoggerFactory.getLogger(Encryptor.class);
  
--    private static final Map<String, Encryptor> INSTANCES = new ConcurrentHashMap<String, Encryptor>();
++    private static final Map<String, Encryptor> INSTANCES = new ConcurrentHashMap<>();
  
      private static final String DEFAULT_SECRET_KEY = "1abcdefghilmnopqrstuvz2!";
  

http://git-wip-us.apache.org/repos/asf/syncope/blob/4115c57b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AttributableUtils.java
----------------------------------------------------------------------
diff --cc core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AttributableUtils.java
index b36cd18,0000000..9539604
mode 100644,000000..100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AttributableUtils.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AttributableUtils.java
@@@ -1,91 -1,0 +1,89 @@@
 +/*
 + * 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.persistence.api.entity;
 +
 +import java.util.List;
 +import org.apache.syncope.common.lib.to.AbstractAttributableTO;
 +import org.apache.syncope.common.lib.to.AbstractSubjectTO;
 +import org.apache.syncope.common.lib.types.AttributableType;
 +import org.apache.syncope.common.lib.types.IntMappingType;
 +import org.apache.syncope.common.lib.types.MappingPurpose;
 +
 +public interface AttributableUtils {
 +
 +    AttributableType getType();
 +
 +    <T extends Attributable<?, ?, ?>> Class<T> attributableClass();
 +
 +    <T extends PlainSchema> Class<T> plainSchemaClass();
 +
 +    <T extends PlainSchema> T newPlainSchema();
 +
 +    <T extends PlainAttr> Class<T> plainAttrClass();
 +
 +    <T extends PlainAttr> T newPlainAttr();
 +
 +    <T extends PlainAttrValue> Class<T> plainAttrValueClass();
 +
 +    <T extends PlainAttrValue> T newPlainAttrValue();
 +
 +    <T extends AttrTemplate<PlainSchema>> Class<T> plainAttrTemplateClass();
 +
 +    <T extends PlainAttrValue> Class<T> plainAttrUniqueValueClass();
 +
 +    <T extends PlainAttrValue> T newPlainAttrUniqueValue();
 +
 +    <T extends DerSchema> Class<T> derSchemaClass();
 +
 +    <T extends DerSchema> T newDerSchema();
 +
 +    <T extends DerAttr> Class<T> derAttrClass();
 +
 +    <T extends DerAttr> T newDerAttr();
 +
 +    <T extends AttrTemplate<DerSchema>> Class<T> derAttrTemplateClass();
 +
 +    <T extends VirSchema> Class<T> virSchemaClass();
 +
 +    <T extends VirSchema> T newVirSchema();
 +
 +    <T extends VirAttr> Class<T> virAttrClass();
 +
 +    <T extends VirAttr> T newVirAttr();
 +
 +    <T extends AttrTemplate<VirSchema>> Class<T> virAttrTemplateClass();
 +
 +    <T extends MappingItem> T getAccountIdItem(ExternalResource resource);
 +
 +    String getAccountLink(ExternalResource resource);
 +
 +    <T extends MappingItem> List<T> getMappingItems(ExternalResource resource, MappingPurpose purpose);
 +
-     <T extends MappingItem> List<T> getUidToMappingItems(ExternalResource resource, MappingPurpose purpose);
- 
 +    IntMappingType plainIntMappingType();
 +
 +    IntMappingType derIntMappingType();
 +
 +    IntMappingType virIntMappingType();
 +
 +    <T extends MappingItem> Class<T> mappingItemClass();
 +
 +    <T extends AbstractAttributableTO> T newAttributableTO();
 +
 +    <T extends AbstractSubjectTO> T newSubjectTO();
 +}


Mime
View raw message