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 2015/10/29 10:40:09 UTC
[08/10] syncope git commit: [SYNCOPE-141] Preliminary changes
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/utils/ConnObjectUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/ConnObjectUtils.java
new file mode 100644
index 0000000..97bf8d8
--- /dev/null
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/ConnObjectUtils.java
@@ -0,0 +1,259 @@
+/*
+ * 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.utils;
+
+import org.apache.syncope.core.misc.policy.InvalidPasswordRuleConf;
+import org.apache.syncope.core.misc.security.SecureRandomUtils;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.AnyOperations;
+import org.apache.syncope.common.lib.patch.AnyPatch;
+import org.apache.syncope.common.lib.policy.PasswordRuleConf;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
+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.misc.security.Encryptor;
+import org.apache.syncope.core.misc.security.PasswordGenerator;
+import org.apache.syncope.core.persistence.api.dao.RealmDAO;
+import org.apache.syncope.core.persistence.api.entity.Realm;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class ConnObjectUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConnObjectUtils.class);
+
+ private static final Encryptor ENCRYPTOR = Encryptor.getInstance();
+
+ @Autowired
+ private TemplateUtils templateUtils;
+
+ @Autowired
+ private RealmDAO realmDAO;
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private ExternalResourceDAO resourceDAO;
+
+ @Autowired
+ private PasswordGenerator passwordGenerator;
+
+ @Autowired
+ private MappingUtils mappingUtils;
+
+ /**
+ * Extract password value from passed value (if instance of GuardedString or GuardedByteArray).
+ *
+ * @param pwd received from the underlying connector
+ * @return password value
+ */
+ public static 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();
+ }
+
+ /**
+ * Build a UserTO / GroupTO / AnyObjectTO out of connector object attributes and schema mapping.
+ *
+ * @param obj connector object
+ * @param syncTask synchronization task
+ * @param provision provision information
+ * @param anyUtils utils
+ * @param <T> any object
+ * @return UserTO for the user to be created
+ */
+ @Transactional(readOnly = true)
+ public <T extends AnyTO> T getAnyTO(
+ final ConnectorObject obj, final SyncTask syncTask, final Provision provision, final AnyUtils anyUtils) {
+
+ T anyTO = getAnyTOFromConnObject(obj, syncTask, provision, anyUtils);
+
+ // (for users) if password was not set above, generate
+ if (anyTO instanceof UserTO && StringUtils.isBlank(((UserTO) anyTO).getPassword())) {
+ final UserTO userTO = (UserTO) anyTO;
+
+ List<PasswordRuleConf> ruleConfs = new ArrayList<>();
+
+ Realm realm = realmDAO.find(userTO.getRealm());
+ if (realm != null) {
+ for (Realm ancestor : realmDAO.findAncestors(realm)) {
+ if (ancestor.getPasswordPolicy() != null) {
+ ruleConfs.addAll(ancestor.getPasswordPolicy().getRuleConfs());
+ }
+ }
+ }
+
+ for (String resName : userTO.getResources()) {
+ ExternalResource resource = resourceDAO.find(resName);
+ if (resource != null && resource.getPasswordPolicy() != null) {
+ ruleConfs.addAll(resource.getPasswordPolicy().getRuleConfs());
+ }
+ }
+
+ String password;
+ try {
+ password = passwordGenerator.generate(ruleConfs);
+ } catch (InvalidPasswordRuleConf e) {
+ LOG.error("Could not generate policy-compliant random password for {}", userTO, e);
+
+ password = SecureRandomUtils.generateRandomPassword(16);
+ }
+ userTO.setPassword(password);
+ }
+
+ return anyTO;
+ }
+
+ /**
+ * Build {@link AnyPatch} out of connector object attributes and schema mapping.
+ *
+ * @param key any object to be updated
+ * @param obj connector object
+ * @param original any object to get diff from
+ * @param syncTask synchronization task
+ * @param provision provision information
+ * @param anyUtils utils
+ * @param <T> any object
+ * @return modifications for the any object to be updated
+ */
+ @SuppressWarnings("unchecked")
+ @Transactional(readOnly = true)
+ public <T extends AnyPatch> T getAnyPatch(final Long key, final ConnectorObject obj,
+ final AnyTO original, final SyncTask syncTask, final Provision provision, final AnyUtils anyUtils) {
+
+ AnyTO updated = getAnyTOFromConnObject(obj, syncTask, provision, anyUtils);
+ updated.setKey(key);
+
+ if (AnyTypeKind.USER == anyUtils.getAnyTypeKind()) {
+ // update password if and only if password is really changed
+ User user = userDAO.authFind(key);
+ if (StringUtils.isBlank(((UserTO) updated).getPassword())
+ || ENCRYPTOR.verify(((UserTO) updated).getPassword(),
+ user.getCipherAlgorithm(), user.getPassword())) {
+
+ ((UserTO) updated).setPassword(null);
+ }
+ return (T) AnyOperations.diff(((UserTO) updated), ((UserTO) original), true);
+ } else if (AnyTypeKind.GROUP == anyUtils.getAnyTypeKind()) {
+ return (T) AnyOperations.diff(((GroupTO) updated), ((GroupTO) original), true);
+ } else if (AnyTypeKind.ANY_OBJECT == anyUtils.getAnyTypeKind()) {
+ return (T) AnyOperations.diff(((AnyObjectTO) updated), ((AnyObjectTO) original), true);
+ }
+
+ return null;
+ }
+
+ private <T extends AnyTO> T getAnyTOFromConnObject(final ConnectorObject obj,
+ final SyncTask syncTask, final Provision provision, final AnyUtils anyUtils) {
+
+ T anyTO = anyUtils.newAnyTO();
+ anyTO.setType(provision.getAnyType().getKey());
+
+ // 1. fill with data from connector object
+ anyTO.setRealm(syncTask.getDestinatioRealm().getFullPath());
+ for (MappingItem item : MappingUtils.getSyncMappingItems(provision)) {
+ mappingUtils.setIntValues(item, obj.getAttributeByName(item.getExtAttrName()), anyTO, anyUtils);
+ }
+
+ // 2. add data from defined template (if any)
+ templateUtils.apply(anyTO, syncTask.getTemplate(provision.getAnyType()));
+
+ return anyTO;
+ }
+
+ /**
+ * 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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/ExceptionUtils2.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/utils/ExceptionUtils2.java b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/ExceptionUtils2.java
new file mode 100644
index 0000000..76ba64f
--- /dev/null
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/ExceptionUtils2.java
@@ -0,0 +1,47 @@
+/*
+ * 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.utils;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+
+public final class ExceptionUtils2 {
+
+ /**
+ * Uses commons lang's ExceptionUtils to provide a representation of the full stack trace of the given throwable.
+ *
+ * @param t throwable to build stack trace from
+ * @return a string representation of full stack trace of the given throwable
+ */
+ public static String getFullStackTrace(final Throwable t) {
+ StringBuilder result = new StringBuilder();
+
+ for (Throwable throwable : ExceptionUtils.getThrowableList(t)) {
+ result.append(ExceptionUtils.getMessage(throwable)).append('\n').
+ append(ExceptionUtils.getStackTrace(throwable)).append("\n\n");
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Private default constructor, for static-only classes.
+ */
+ private ExceptionUtils2() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/FormatUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/utils/FormatUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/FormatUtils.java
new file mode 100644
index 0000000..ec5250a
--- /dev/null
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/FormatUtils.java
@@ -0,0 +1,117 @@
+/*
+ * 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.utils;
+
+import java.text.DecimalFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.apache.commons.lang3.time.DateUtils;
+import org.apache.syncope.common.lib.SyncopeConstants;
+
+/**
+ * Utility class for parsing / formatting date and numbers.
+ */
+public final class FormatUtils {
+
+ private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
+
+ @Override
+ protected SimpleDateFormat initialValue() {
+ SimpleDateFormat sdf = new SimpleDateFormat();
+ sdf.applyPattern(SyncopeConstants.DEFAULT_DATE_PATTERN);
+ return sdf;
+ }
+ };
+
+ private static final ThreadLocal<DecimalFormat> DECIMAL_FORMAT = new ThreadLocal<DecimalFormat>() {
+
+ @Override
+ protected DecimalFormat initialValue() {
+ return new DecimalFormat();
+ }
+ };
+
+ public static String format(final Date date) {
+ return format(date, true);
+ }
+
+ public static String format(final Date date, final boolean lenient) {
+ return format(date, lenient, null);
+ }
+
+ public static String format(final Date date, final boolean lenient, final String conversionPattern) {
+ SimpleDateFormat sdf = DATE_FORMAT.get();
+ if (conversionPattern != null) {
+ sdf.applyPattern(conversionPattern);
+ }
+ sdf.setLenient(lenient);
+ return sdf.format(date);
+ }
+
+ public static String format(final long number) {
+ return format(number, null);
+ }
+
+ public static String format(final long number, final String conversionPattern) {
+ DecimalFormat df = DECIMAL_FORMAT.get();
+ if (conversionPattern != null) {
+ df.applyPattern(conversionPattern);
+ }
+ return df.format(number);
+ }
+
+ public static String format(final double number) {
+ return format(number, null);
+ }
+
+ public static String format(final double number, final String conversionPattern) {
+ DecimalFormat df = DECIMAL_FORMAT.get();
+ if (conversionPattern != null) {
+ df.applyPattern(conversionPattern);
+ }
+ return df.format(number);
+ }
+
+ public static Date parseDate(final String source) throws ParseException {
+ return DateUtils.parseDate(source, SyncopeConstants.DATE_PATTERNS);
+ }
+
+ public static Date parseDate(final String source, final String conversionPattern) throws ParseException {
+ SimpleDateFormat sdf = DATE_FORMAT.get();
+ sdf.applyPattern(conversionPattern);
+ sdf.setLenient(false);
+ return sdf.parse(source);
+ }
+
+ public static Number parseNumber(final String source, final String conversionPattern) throws ParseException {
+ DecimalFormat df = DECIMAL_FORMAT.get();
+ df.applyPattern(conversionPattern);
+ return df.parse(source);
+ }
+
+ public static void clear() {
+ DATE_FORMAT.remove();
+ DECIMAL_FORMAT.remove();
+ }
+
+ private FormatUtils() {
+ // private empty constructor
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/MappingUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/utils/MappingUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/MappingUtils.java
new file mode 100644
index 0000000..bc7c6b8
--- /dev/null
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/MappingUtils.java
@@ -0,0 +1,831 @@
+/*
+ * 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.utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.collections4.ListUtils;
+import org.apache.commons.jexl2.JexlContext;
+import org.apache.commons.jexl2.MapContext;
+import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.SerializationUtils;
+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.to.AnyTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+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.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.core.misc.policy.InvalidPasswordRuleConf;
+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.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+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.resource.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.group.GPlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
+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.jexl.JexlUtils;
+import org.apache.syncope.core.misc.security.PasswordGenerator;
+import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
+import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
+import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.Schema;
+import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
+import org.apache.syncope.core.persistence.api.entity.resource.Provision;
+import org.apache.syncope.core.provisioning.api.VirAttrHandler;
+import org.apache.syncope.core.provisioning.api.data.MappingItemTransformer;
+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.OperationOptions;
+import org.identityconnectors.framework.common.objects.OperationOptionsBuilder;
+import org.identityconnectors.framework.common.objects.OperationalAttributes;
+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.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class MappingUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MappingUtils.class);
+
+ private static final Encryptor ENCRYPTOR = Encryptor.getInstance();
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private AnyTypeDAO anyTypeDAO;
+
+ @Autowired
+ private PlainSchemaDAO plainSchemaDAO;
+
+ @Autowired
+ private VirSchemaDAO virSchemaDAO;
+
+ @Autowired
+ private VirAttrHandler virAttrHandler;
+
+ @Autowired
+ private VirAttrCache virAttrCache;
+
+ @Autowired
+ private PasswordGenerator passwordGenerator;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ @Autowired
+ private AnyUtilsFactory anyUtilsFactory;
+
+ public static MappingItem getConnObjectKeyItem(final Provision provision) {
+ Mapping mapping = null;
+ if (provision != null) {
+ mapping = provision.getMapping();
+ }
+
+ return mapping == null
+ ? null
+ : mapping.getConnObjectKeyItem();
+ }
+
+ private static List<MappingItem> getMappingItems(final Provision provision, final MappingPurpose purpose) {
+ List<? extends MappingItem> items = Collections.<MappingItem>emptyList();
+ if (provision != null) {
+ items = provision.getMapping().getItems();
+ }
+
+ List<MappingItem> result = new ArrayList<>();
+
+ switch (purpose) {
+ case SYNCHRONIZATION:
+ for (MappingItem item : items) {
+ if (MappingPurpose.PROPAGATION != item.getPurpose()
+ && MappingPurpose.NONE != item.getPurpose()) {
+
+ result.add(item);
+ }
+ }
+ break;
+
+ case PROPAGATION:
+ for (MappingItem item : items) {
+ if (MappingPurpose.SYNCHRONIZATION != item.getPurpose()
+ && MappingPurpose.NONE != item.getPurpose()) {
+
+ result.add(item);
+ }
+ }
+ break;
+
+ case BOTH:
+ for (MappingItem item : items) {
+ if (MappingPurpose.NONE != item.getPurpose()) {
+ result.add(item);
+ }
+ }
+ break;
+
+ case NONE:
+ for (MappingItem item : items) {
+ if (MappingPurpose.NONE == item.getPurpose()) {
+ result.add(item);
+ }
+ }
+ break;
+
+ default:
+ }
+
+ return result;
+ }
+
+ public static List<MappingItem> getBothMappingItems(final Provision provision) {
+ return getMappingItems(provision, MappingPurpose.BOTH);
+ }
+
+ public static List<MappingItem> getPropagationMappingItems(final Provision provision) {
+ return getMappingItems(provision, MappingPurpose.PROPAGATION);
+ }
+
+ public static List<MappingItem> getSyncMappingItems(final Provision provision) {
+ return getMappingItems(provision, MappingPurpose.SYNCHRONIZATION);
+ }
+
+ /**
+ * Build __NAME__ for propagation. First look if there ia a defined connObjectLink for the given resource (and in
+ * this case evaluate as JEXL); otherwise, take given connObjectKey.
+ *
+ * @param any given any object
+ * @param provision external resource
+ * @param connObjectKey connector object key
+ * @return the value to be propagated as __NAME__
+ */
+ public static Name evaluateNAME(final Any<?, ?> any, final Provision provision, final String connObjectKey) {
+ if (StringUtils.isBlank(connObjectKey)) {
+ // LOG error but avoid to throw exception: leave it to the external resource
+ LOG.error("Missing ConnObjectKey for '{}': ", provision.getResource());
+ }
+
+ // Evaluate connObjectKey expression
+ String connObjectLink = provision == null || provision.getMapping() == null
+ ? null
+ : provision.getMapping().getConnObjectLink();
+ String evalConnObjectLink = null;
+ if (StringUtils.isNotBlank(connObjectLink)) {
+ JexlContext jexlContext = new MapContext();
+ JexlUtils.addFieldsToContext(any, jexlContext);
+ JexlUtils.addPlainAttrsToContext(any.getPlainAttrs(), jexlContext);
+ JexlUtils.addDerAttrsToContext(any.getDerAttrs(), any.getPlainAttrs(), jexlContext);
+ evalConnObjectLink = JexlUtils.evaluate(connObjectLink, jexlContext);
+ }
+
+ // If connObjectLink evaluates to an empty string, just use the provided connObjectKey as Name(),
+ // otherwise evaluated connObjectLink expression is taken as Name().
+ Name name;
+ if (StringUtils.isBlank(evalConnObjectLink)) {
+ // add connObjectKey as __NAME__ attribute ...
+ LOG.debug("Add connObjectKey [{}] as __NAME__", connObjectKey);
+ name = new Name(connObjectKey);
+ } else {
+ LOG.debug("Add connObjectLink [{}] as __NAME__", evalConnObjectLink);
+ name = new Name(evalConnObjectLink);
+
+ // connObjectKey not propagated: it will be used to set the value for __UID__ attribute
+ LOG.debug("connObjectKey will be used just as __UID__ attribute");
+ }
+
+ return name;
+ }
+
+ public static List<MappingItemTransformer> getMappingItemTransformers(final MappingItem mappingItem) {
+ List<MappingItemTransformer> result = new ArrayList<>();
+
+ for (String className : mappingItem.getMappingItemTransformerClassNames()) {
+ try {
+ Class<?> transformerClass = ClassUtils.getClass(className);
+
+ result.add((MappingItemTransformer) ApplicationContextProvider.
+ getBeanFactory().
+ createBean(transformerClass, AbstractBeanDefinition.AUTOWIRE_BY_NAME, false));
+ } catch (Exception e) {
+ LOG.error("Could not instantiate {}, ignoring...", className, e);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Build options for requesting all mapped connector attributes.
+ *
+ * @param mapItems mapping items
+ * @return options for requesting all mapped connector attributes
+ * @see OperationOptions
+ */
+ public static OperationOptions buildOperationOptions(final Iterator<? extends MappingItem> mapItems) {
+ OperationOptionsBuilder builder = new OperationOptionsBuilder();
+
+ Set<String> attrsToGet = new HashSet<>();
+ attrsToGet.add(Name.NAME);
+ attrsToGet.add(Uid.NAME);
+ attrsToGet.add(OperationalAttributes.ENABLE_NAME);
+
+ while (mapItems.hasNext()) {
+ MappingItem mapItem = mapItems.next();
+ if (mapItem.getPurpose() != MappingPurpose.NONE) {
+ attrsToGet.add(mapItem.getExtAttrName());
+ }
+ }
+
+ builder.setAttributesToGet(attrsToGet);
+ // -------------------------------------
+
+ return builder.build();
+ }
+
+ /**
+ * Prepare attributes for sending to a connector instance.
+ *
+ * @param any given any object
+ * @param password clear-text password
+ * @param changePwd whether password should be included for propagation attributes or not
+ * @param enable whether any object must be enabled or not
+ * @param provision provision information
+ * @return connObjectLink + prepared attributes
+ */
+ @Transactional(readOnly = true)
+ public Pair<String, Set<Attribute>> prepareAttrs(
+ final Any<?, ?> any,
+ final String password,
+ final boolean changePwd,
+ final Boolean enable,
+ final Provision provision) {
+
+ LOG.debug("Preparing resource attributes for {} with provision {} for attributes {}",
+ any, provision, any.getPlainAttrs());
+
+ Set<Attribute> attributes = new HashSet<>();
+ String connObjectKey = null;
+
+ for (MappingItem mappingItem : getMappingItems(provision, MappingPurpose.PROPAGATION)) {
+ LOG.debug("Processing schema {}", mappingItem.getIntAttrName());
+
+ try {
+ Pair<String, Attribute> preparedAttr = prepareAttr(provision, mappingItem, any, password);
+
+ if (preparedAttr != null && preparedAttr.getKey() != null) {
+ connObjectKey = 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", mappingItem.getIntAttrName(), e);
+ }
+ }
+
+ Attribute connObjectKeyExtAttr =
+ AttributeUtil.find(getConnObjectKeyItem(provision).getExtAttrName(), attributes);
+ if (connObjectKeyExtAttr != null) {
+ attributes.remove(connObjectKeyExtAttr);
+ attributes.add(AttributeBuilder.build(getConnObjectKeyItem(provision).getExtAttrName(), connObjectKey));
+ }
+ attributes.add(evaluateNAME(any, provision, connObjectKey));
+
+ 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<>(connObjectKey, attributes);
+ }
+
+ /**
+ * Prepare an attribute to be sent to a connector instance.
+ *
+ * @param provision external resource
+ * @param mapItem mapping item for the given attribute
+ * @param any any object
+ * @param password clear-text password
+ * @return connObjectLink + prepared attribute
+ */
+ private Pair<String, Attribute> prepareAttr(
+ final Provision provision, final MappingItem mapItem, final Any<?, ?> any, final String password) {
+
+ List<Any<?, ?>> anys = new ArrayList<>();
+
+ switch (mapItem.getIntMappingType().getAnyTypeKind()) {
+ case USER:
+ if (any instanceof User) {
+ anys.add(any);
+ }
+ break;
+
+ case GROUP:
+ if (any instanceof User) {
+ for (Group group : userDAO.findAllGroups((User) any)) {
+ anys.add(group);
+ }
+ } else if (any instanceof Group) {
+ anys.add(any);
+ }
+ break;
+
+ case ANY_OBJECT:
+ if (any instanceof AnyObject) {
+ anys.add(any);
+ }
+ break;
+
+ default:
+ }
+
+ Schema schema = null;
+ boolean readOnlyVirSchema = false;
+ AttrSchemaType schemaType;
+ Pair<String, Attribute> result;
+
+ switch (mapItem.getIntMappingType()) {
+ case UserPlainSchema:
+ case GroupPlainSchema:
+ case AnyObjectPlainSchema:
+ schema = plainSchemaDAO.find(mapItem.getIntAttrName());
+ schemaType = schema == null ? AttrSchemaType.String : schema.getType();
+ break;
+
+ case UserVirtualSchema:
+ case GroupVirtualSchema:
+ case AnyObjectVirtualSchema:
+ schema = virSchemaDAO.find(mapItem.getIntAttrName());
+ readOnlyVirSchema = (schema != null && schema.isReadonly());
+ schemaType = AttrSchemaType.String;
+ break;
+
+ default:
+ schemaType = AttrSchemaType.String;
+ }
+
+ String extAttrName = mapItem.getExtAttrName();
+
+ List<PlainAttrValue> values = getIntValues(provision, mapItem, anys);
+
+ LOG.debug("Define mapping for: "
+ + "\n* ExtAttrName " + extAttrName
+ + "\n* is connObjectKey " + mapItem.isConnObjectKey()
+ + "\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 {
+ 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.isConnObjectKey()) {
+ result = new ImmutablePair<>(objValues.iterator().next().toString(), null);
+ } else if (mapItem.isPassword() && any instanceof User) {
+ String passwordAttrValue = password;
+ if (StringUtils.isBlank(passwordAttrValue)) {
+ User user = (User) any;
+ 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 (provision.getResource().isRandomPwdIfNotProvided()) {
+ try {
+ passwordAttrValue = passwordGenerator.generate(user);
+ } catch (InvalidPasswordRuleConf 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())
+ || anyUtilsFactory.getInstance(any).getAnyTypeKind()
+ != mapItem.getIntMappingType().getAnyTypeKind()) {
+
+ 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;
+ }
+
+ private String getGroupOwnerValue(final Provision provision, final Any<?, ?> any) {
+ Pair<String, Attribute> preparedAttr = prepareAttr(provision, getConnObjectKeyItem(provision), any, null);
+ String connObjectKey = preparedAttr.getKey();
+
+ return evaluateNAME(any, provision, connObjectKey).getNameValue();
+ }
+
+ /**
+ * Get attribute values for the given {@link MappingItem} and any objects.
+ *
+ * @param provision provision information
+ * @param mappingItem mapping item
+ * @param anys any objects
+ * @return attribute values.
+ */
+ @Transactional(readOnly = true)
+ public List<PlainAttrValue> getIntValues(final Provision provision,
+ final MappingItem mappingItem, final List<Any<?, ?>> anys) {
+
+ LOG.debug("Get attributes for '{}' and mapping type '{}'", anys, mappingItem.getIntMappingType());
+
+ boolean transform = true;
+
+ List<PlainAttrValue> values = new ArrayList<>();
+ switch (mappingItem.getIntMappingType()) {
+ case UserPlainSchema:
+ case GroupPlainSchema:
+ case AnyObjectPlainSchema:
+ for (Any<?, ?> any : anys) {
+ PlainAttr<?> attr = any.getPlainAttr(mappingItem.getIntAttrName());
+ if (attr != null) {
+ if (attr.getUniqueValue() != null) {
+ PlainAttrUniqueValue value = SerializationUtils.clone(attr.getUniqueValue());
+ value.setAttr(null);
+ values.add(value);
+ } else if (attr.getValues() != null) {
+ for (PlainAttrValue value : attr.getValues()) {
+ PlainAttrValue shadow = SerializationUtils.clone(value);
+ shadow.setAttr(null);
+ values.add(shadow);
+ }
+ }
+ }
+
+ LOG.debug("Retrieved attribute {}"
+ + "\n* IntAttrName {}"
+ + "\n* IntMappingType {}"
+ + "\n* Attribute values {}",
+ attr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+ }
+
+ break;
+
+ case UserDerivedSchema:
+ case GroupDerivedSchema:
+ case AnyObjectDerivedSchema:
+ for (Any<?, ?> any : anys) {
+ AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
+ DerAttr<?> attr = any.getDerAttr(mappingItem.getIntAttrName());
+ if (attr != null) {
+ PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+ attrValue.setStringValue(attr.getValue(any.getPlainAttrs()));
+ values.add(attrValue);
+ }
+
+ LOG.debug("Retrieved attribute {}"
+ + "\n* IntAttrName {}"
+ + "\n* IntMappingType {}"
+ + "\n* Attribute values {}",
+ attr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+ }
+ break;
+
+ case UserVirtualSchema:
+ case GroupVirtualSchema:
+ case AnyObjectVirtualSchema:
+ // virtual attributes don't get transformed
+ transform = false;
+
+ VirSchema virSchema = virSchemaDAO.find(mappingItem.getIntAttrName());
+ if (virSchema != null) {
+ for (Any<?, ?> any : anys) {
+ LOG.debug("Expire entry cache {}-{}", any.getKey(), mappingItem.getIntAttrName());
+ virAttrCache.expire(any.getType().getKey(), any.getKey(), mappingItem.getIntAttrName());
+
+ AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
+ for (String value : virAttrHandler.getValues(any, virSchema)) {
+ PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+ attrValue.setStringValue(value);
+ values.add(attrValue);
+ }
+
+ LOG.debug("Retrieved values for {}"
+ + "\n* IntAttrName {}"
+ + "\n* IntMappingType {}"
+ + "\n* Attribute values {}",
+ virSchema.getKey(), mappingItem.getIntAttrName(), mappingItem.getIntMappingType(),
+ values);
+ }
+ }
+ break;
+
+ case UserKey:
+ case GroupKey:
+ case AnyObjectKey:
+ for (Any<?, ?> any : anys) {
+ AnyUtils anyUtils = anyUtilsFactory.getInstance(any);
+ PlainAttrValue attrValue = anyUtils.newPlainAttrValue();
+ attrValue.setStringValue(any.getKey().toString());
+ values.add(attrValue);
+ }
+ break;
+
+ case Username:
+ for (Any<?, ?> any : anys) {
+ if (any instanceof User) {
+ UPlainAttrValue attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+ attrValue.setStringValue(((User) any).getUsername());
+ values.add(attrValue);
+ }
+ }
+ break;
+
+ case GroupName:
+ for (Any<?, ?> any : anys) {
+ if (any instanceof Group) {
+ GPlainAttrValue attrValue = entityFactory.newEntity(GPlainAttrValue.class);
+ attrValue.setStringValue(((Group) any).getName());
+ values.add(attrValue);
+ }
+ }
+ break;
+
+ case GroupOwnerSchema:
+ Mapping uMapping = provision.getAnyType().equals(anyTypeDAO.findUser())
+ ? null
+ : provision.getMapping();
+ Mapping gMapping = provision.getAnyType().equals(anyTypeDAO.findGroup())
+ ? null
+ : provision.getMapping();
+
+ for (Any<?, ?> any : anys) {
+ if (any instanceof Group) {
+ Group group = (Group) any;
+ String groupOwnerValue = null;
+ if (group.getUserOwner() != null && uMapping != null) {
+ groupOwnerValue = getGroupOwnerValue(provision, group.getUserOwner());
+ }
+ if (group.getGroupOwner() != null && gMapping != null) {
+ groupOwnerValue = getGroupOwnerValue(provision, group.getGroupOwner());
+ }
+
+ if (StringUtils.isNotBlank(groupOwnerValue)) {
+ GPlainAttrValue attrValue = entityFactory.newEntity(GPlainAttrValue.class);
+ attrValue.setStringValue(groupOwnerValue);
+ values.add(attrValue);
+ }
+ }
+ }
+ break;
+
+ default:
+ }
+
+ LOG.debug("Values for propagation: {}", values);
+
+ List<PlainAttrValue> transformed = values;
+ if (transform) {
+ for (MappingItemTransformer transformer : getMappingItemTransformers(mappingItem)) {
+ transformed = transformer.beforePropagation(transformed);
+ }
+ LOG.debug("Transformed values for propagation: {}", values);
+ } else {
+ LOG.debug("No transformation occurred");
+ }
+
+ return transformed;
+ }
+
+ /**
+ * Get connObjectKey internal value.
+ *
+ * @param any any object
+ * @param provision provision information
+ * @return connObjectKey internal value
+ */
+ @Transactional(readOnly = true)
+ public String getConnObjectKeyValue(final Any<?, ?> any, final Provision provision) {
+ List<PlainAttrValue> values = getIntValues(provision, provision.getMapping().getConnObjectKeyItem(),
+ Collections.<Any<?, ?>>singletonList(any));
+ return values == null || values.isEmpty()
+ ? null
+ : values.get(0).getValueAsString();
+ }
+
+ /**
+ * Set attribute values, according to the given {@link MappingItem}, to any object from attribute received from
+ * connector.
+ *
+ * @param <T> any object
+ * @param mappingItem mapping item
+ * @param attr attribute received from connector
+ * @param anyTO any object
+ * @param anyUtils any utils
+ */
+ @Transactional(readOnly = true)
+ public <T extends AnyTO> void setIntValues(
+ final MappingItem mappingItem, final Attribute attr, final T anyTO, final AnyUtils anyUtils) {
+
+ List<Object> values = null;
+ if (attr != null) {
+ values = attr.getValue();
+ for (MappingItemTransformer transformer : getMappingItemTransformers(mappingItem)) {
+ values = transformer.beforeSync(values);
+ }
+ }
+ values = ListUtils.emptyIfNull(values);
+
+ switch (mappingItem.getIntMappingType()) {
+ case UserKey:
+ case GroupKey:
+ case AnyObjectKey:
+ break;
+
+ case Password:
+ if (anyTO instanceof UserTO && !values.isEmpty()) {
+ ((UserTO) anyTO).setPassword(ConnObjectUtils.getPassword(values.get(0)));
+ }
+ break;
+
+ case Username:
+ if (anyTO instanceof UserTO) {
+ ((UserTO) anyTO).setUsername(values.isEmpty() || values.get(0) == null
+ ? null
+ : values.get(0).toString());
+ }
+ break;
+
+ case GroupName:
+ if (anyTO instanceof GroupTO) {
+ ((GroupTO) anyTO).setName(values.isEmpty() || values.get(0) == null
+ ? null
+ : values.get(0).toString());
+ }
+ break;
+
+ case GroupOwnerSchema:
+ if (anyTO instanceof GroupTO && attr != null) {
+ // using a special attribute (with schema "", that will be ignored) for carrying the
+ // GroupOwnerSchema value
+ AttrTO attrTO = new AttrTO();
+ attrTO.setSchema(StringUtils.EMPTY);
+ if (values.isEmpty() || values.get(0) == null) {
+ attrTO.getValues().add(StringUtils.EMPTY);
+ } else {
+ attrTO.getValues().add(values.get(0).toString());
+ }
+
+ ((GroupTO) anyTO).getPlainAttrs().add(attrTO);
+ }
+ break;
+
+ case UserPlainSchema:
+ case GroupPlainSchema:
+ case AnyObjectPlainSchema:
+ AttrTO attrTO = new AttrTO();
+ attrTO.setSchema(mappingItem.getIntAttrName());
+
+ PlainSchema schema = plainSchemaDAO.find(mappingItem.getIntAttrName());
+
+ for (Object value : values) {
+ AttrSchemaType schemaType = schema == null ? AttrSchemaType.String : schema.getType();
+ if (value != null) {
+ PlainAttrValue attrValue = anyUtils.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;
+ }
+ attrTO.getValues().add(attrValue.getValueAsString(schemaType));
+ }
+ }
+
+ anyTO.getPlainAttrs().add(attrTO);
+ break;
+
+ case UserDerivedSchema:
+ case GroupDerivedSchema:
+ case AnyObjectDerivedSchema:
+ attrTO = new AttrTO();
+ attrTO.setSchema(mappingItem.getIntAttrName());
+ anyTO.getDerAttrs().add(attrTO);
+ break;
+
+ case UserVirtualSchema:
+ case GroupVirtualSchema:
+ case AnyObjectVirtualSchema:
+ attrTO = new AttrTO();
+ attrTO.setSchema(mappingItem.getIntAttrName());
+
+ // virtual attributes don't get transformed, iterate over original attr.getValue()
+ for (Object value : (attr == null || attr.getValue() == null)
+ ? Collections.emptyList() : attr.getValue()) {
+
+ if (value != null) {
+ attrTO.getValues().add(value.toString());
+ }
+ }
+
+ anyTO.getVirAttrs().add(attrTO);
+ break;
+
+ default:
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/RealmUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/utils/RealmUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/RealmUtils.java
new file mode 100644
index 0000000..cddda67
--- /dev/null
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/RealmUtils.java
@@ -0,0 +1,61 @@
+/*
+ * 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.utils;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+public final class RealmUtils {
+
+ public static String getGroupOwnerRealm(final String realmPath, final Long groupKey) {
+ return realmPath + "@" + groupKey;
+ }
+
+ public static boolean normalizingAddTo(final Set<String> realms, final String newRealm) {
+ boolean dontAdd = false;
+ Set<String> toRemove = new HashSet<>();
+ for (String realm : realms) {
+ if (newRealm.startsWith(realm)) {
+ dontAdd = true;
+ } else if (realm.startsWith(newRealm)) {
+ toRemove.add(realm);
+ }
+ }
+
+ realms.removeAll(toRemove);
+ if (!dontAdd) {
+ realms.add(newRealm);
+ }
+ return !dontAdd;
+ }
+
+ public static Set<String> normalize(final Collection<String> realms) {
+ Set<String> normalized = new HashSet<>();
+ for (String realm : realms) {
+ normalizingAddTo(normalized, realm);
+ }
+
+ return normalized;
+ }
+
+ private RealmUtils() {
+ // empty constructor for static utility class
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/TemplateUtils.java
----------------------------------------------------------------------
diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/utils/TemplateUtils.java b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/TemplateUtils.java
new file mode 100644
index 0000000..4b990f2
--- /dev/null
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/utils/TemplateUtils.java
@@ -0,0 +1,223 @@
+/*
+ * 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.utils;
+
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.RelationshipTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.core.misc.jexl.JexlUtils;
+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.AnyTemplate;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.user.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class TemplateUtils {
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private GroupDAO groupDAO;
+
+ private AttrTO evaluateAttr(final AnyTO anyTO, 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, anyTO);
+ if (StringUtils.isNotBlank(evaluated)) {
+ result.getValues().add(evaluated);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private void fill(final AnyTO anyTO, final AnyTO template) {
+ if (template.getRealm() != null) {
+ anyTO.setRealm(template.getRealm());
+ }
+
+ Map<String, AttrTO> currentAttrMap = anyTO.getPlainAttrMap();
+ for (AttrTO templatePlainAttr : template.getPlainAttrs()) {
+ if (!templatePlainAttr.getValues().isEmpty()
+ && (!currentAttrMap.containsKey(templatePlainAttr.getSchema())
+ || currentAttrMap.get(templatePlainAttr.getSchema()).getValues().isEmpty())) {
+
+ anyTO.getPlainAttrs().add(evaluateAttr(anyTO, templatePlainAttr));
+ }
+ }
+
+ currentAttrMap = anyTO.getDerAttrMap();
+ for (AttrTO templateDerAttr : template.getDerAttrs()) {
+ if (!currentAttrMap.containsKey(templateDerAttr.getSchema())) {
+ anyTO.getDerAttrs().add(templateDerAttr);
+ }
+ }
+
+ currentAttrMap = anyTO.getVirAttrMap();
+ for (AttrTO templateVirAttr : template.getVirAttrs()) {
+ if (!templateVirAttr.getValues().isEmpty()
+ && (!currentAttrMap.containsKey(templateVirAttr.getSchema())
+ || currentAttrMap.get(templateVirAttr.getSchema()).getValues().isEmpty())) {
+
+ anyTO.getVirAttrs().add(evaluateAttr(anyTO, templateVirAttr));
+ }
+ }
+
+ for (String resource : template.getResources()) {
+ anyTO.getResources().add(resource);
+ }
+
+ anyTO.getAuxClasses().addAll(template.getAuxClasses());
+ }
+
+ private void fillRelationships(final Map<Long, RelationshipTO> anyRelMap,
+ final List<RelationshipTO> anyRels, final List<RelationshipTO> templateRels) {
+
+ for (RelationshipTO memb : templateRels) {
+ if (!anyRelMap.containsKey(memb.getRightKey())) {
+ anyRels.add(memb);
+ }
+ }
+ }
+
+ private void fillMemberships(final Map<Long, MembershipTO> anyMembMap,
+ final List<MembershipTO> anyMembs, final List<MembershipTO> templateMembs) {
+
+ for (MembershipTO memb : templateMembs) {
+ if (!anyMembMap.containsKey(memb.getRightKey())) {
+ anyMembs.add(memb);
+ }
+ }
+ }
+
+ @Transactional(readOnly = true)
+ public <T extends AnyTO> void apply(final T anyTO, final AnyTemplate anyTemplate) {
+ if (anyTemplate != null) {
+ AnyTO template = anyTemplate.get();
+ fill(anyTO, template);
+
+ if (template instanceof AnyObjectTO) {
+ fillRelationships(((AnyObjectTO) anyTO).getRelationshipMap(),
+ ((AnyObjectTO) anyTO).getRelationships(), ((AnyObjectTO) template).getRelationships());
+ fillMemberships(((AnyObjectTO) anyTO).getMembershipMap(),
+ ((AnyObjectTO) anyTO).getMemberships(), ((AnyObjectTO) template).getMemberships());
+ } else if (template instanceof UserTO) {
+ if (StringUtils.isNotBlank(((UserTO) template).getUsername())) {
+ String evaluated = JexlUtils.evaluate(((UserTO) template).getUsername(), anyTO);
+ if (StringUtils.isNotBlank(evaluated)) {
+ ((UserTO) anyTO).setUsername(evaluated);
+ }
+ }
+
+ if (StringUtils.isNotBlank(((UserTO) template).getPassword())) {
+ String evaluated = JexlUtils.evaluate(((UserTO) template).getPassword(), anyTO);
+ if (StringUtils.isNotBlank(evaluated)) {
+ ((UserTO) anyTO).setPassword(evaluated);
+ }
+ }
+
+ fillRelationships(((UserTO) anyTO).getRelationshipMap(),
+ ((UserTO) anyTO).getRelationships(), ((UserTO) template).getRelationships());
+ fillMemberships(((UserTO) anyTO).getMembershipMap(),
+ ((UserTO) anyTO).getMemberships(), ((UserTO) template).getMemberships());
+ } else if (template instanceof GroupTO) {
+ if (StringUtils.isNotBlank(((GroupTO) template).getName())) {
+ String evaluated = JexlUtils.evaluate(((GroupTO) template).getName(), anyTO);
+ if (StringUtils.isNotBlank(evaluated)) {
+ ((GroupTO) anyTO).setName(evaluated);
+ }
+ }
+
+ if (((GroupTO) template).getUserOwner() != null) {
+ final User userOwner = userDAO.find(((GroupTO) template).getUserOwner());
+ if (userOwner != null) {
+ ((GroupTO) anyTO).setUserOwner(userOwner.getKey());
+ }
+ }
+ if (((GroupTO) template).getGroupOwner() != null) {
+ final Group groupOwner = groupDAO.find(((GroupTO) template).getGroupOwner());
+ if (groupOwner != null) {
+ ((GroupTO) anyTO).setGroupOwner(groupOwner.getKey());
+ }
+ }
+ }
+ }
+ }
+
+ public void check(final Map<String, AnyTO> templates, final ClientExceptionType clientExceptionType) {
+ SyncopeClientException sce = SyncopeClientException.build(clientExceptionType);
+
+ for (Map.Entry<String, AnyTO> entry : templates.entrySet()) {
+ for (AttrTO attrTO : entry.getValue().getPlainAttrs()) {
+ if (!attrTO.getValues().isEmpty() && !JexlUtils.isExpressionValid(attrTO.getValues().get(0))) {
+ sce.getElements().add("Invalid JEXL: " + attrTO.getValues().get(0));
+ }
+ }
+
+ for (AttrTO attrTO : entry.getValue().getVirAttrs()) {
+ if (!attrTO.getValues().isEmpty() && !JexlUtils.isExpressionValid(attrTO.getValues().get(0))) {
+ sce.getElements().add("Invalid JEXL: " + attrTO.getValues().get(0));
+ }
+ }
+
+ if (entry.getValue() instanceof UserTO) {
+ UserTO template = (UserTO) entry.getValue();
+ if (StringUtils.isNotBlank(template.getUsername())
+ && !JexlUtils.isExpressionValid(template.getUsername())) {
+
+ sce.getElements().add("Invalid JEXL: " + template.getUsername());
+ }
+ if (StringUtils.isNotBlank(template.getPassword())
+ && !JexlUtils.isExpressionValid(template.getPassword())) {
+
+ sce.getElements().add("Invalid JEXL: " + template.getPassword());
+ }
+ } else if (entry.getValue() instanceof GroupTO) {
+ GroupTO template = (GroupTO) entry.getValue();
+ if (StringUtils.isNotBlank(template.getName())
+ && !JexlUtils.isExpressionValid(template.getName())) {
+
+ sce.getElements().add("Invalid JEXL: " + template.getName());
+ }
+ }
+ }
+
+ if (!sce.isEmpty()) {
+ throw sce;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/misc/src/main/resources/utilsContext.xml
----------------------------------------------------------------------
diff --git a/core/misc/src/main/resources/utilsContext.xml b/core/misc/src/main/resources/utilsContext.xml
new file mode 100644
index 0000000..7b2c9b3
--- /dev/null
+++ b/core/misc/src/main/resources/utilsContext.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context.xsd">
+
+ <bean class="org.apache.syncope.core.misc.AuditManager"/>
+
+ <context:component-scan base-package="org.apache.syncope.core.misc.utils"/>
+
+</beans>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
index 125b447..9cf2b32 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/ContentLoaderHandler.java
@@ -27,7 +27,7 @@ import java.util.Map;
import javax.sql.DataSource;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
-import org.apache.syncope.core.misc.FormatUtils;
+import org.apache.syncope.core.misc.utils.FormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
index 9512849..3c8b0ad 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/content/XMLContentExporter.java
@@ -50,7 +50,7 @@ import javax.xml.transform.stream.StreamResult;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.SyncopeConstants;
-import org.apache.syncope.core.misc.FormatUtils;
+import org.apache.syncope.core.misc.utils.FormatUtils;
import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
import org.apache.syncope.core.persistence.api.content.ContentExporter;
import org.apache.syncope.core.persistence.jpa.entity.JPAReportExec;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
index 2acd683..f02b4ba 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnySearchDAO.java
@@ -39,7 +39,7 @@ import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.AttrSchemaType;
-import org.apache.syncope.core.misc.RealmUtils;
+import org.apache.syncope.core.misc.utils.RealmUtils;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index 4c29c90..86e6275 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -38,7 +38,7 @@ import org.apache.syncope.core.persistence.api.entity.group.Group;
import org.apache.syncope.core.persistence.api.entity.user.User;
import org.apache.syncope.core.persistence.jpa.entity.group.JPAGroup;
import org.apache.syncope.common.lib.types.PropagationByResource;
-import org.apache.syncope.core.misc.RealmUtils;
+import org.apache.syncope.core.misc.utils.RealmUtils;
import org.apache.syncope.core.misc.search.SearchCondConverter;
import org.apache.syncope.core.misc.security.AuthContextUtils;
import org.apache.syncope.core.misc.security.DelegatedAdministrationException;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
index 7032df6..754da9f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractPlainAttrValue.java
@@ -32,7 +32,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.syncope.common.lib.types.AttrSchemaType;
-import org.apache.syncope.core.misc.FormatUtils;
+import org.apache.syncope.core.misc.utils.FormatUtils;
import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
index 8640c50..126c1e1 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ConnectorFacadeProxy.java
@@ -31,7 +31,7 @@ import org.apache.commons.collections4.Transformer;
import org.apache.syncope.common.lib.types.ConnConfProperty;
import org.apache.syncope.common.lib.types.ConnectorCapability;
import org.apache.syncope.common.lib.types.ResourceOperation;
-import org.apache.syncope.core.misc.MappingUtils;
+import org.apache.syncope.core.misc.utils.MappingUtils;
import org.apache.syncope.core.persistence.api.entity.ConnInstance;
import org.apache.syncope.core.provisioning.api.ConnIdBundleManager;
import org.apache.syncope.core.provisioning.api.ConnPoolConfUtils;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
index 94c68ee..182d3cf 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
@@ -28,7 +28,7 @@ import java.util.Map;
import java.util.Set;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.core.misc.MappingUtils;
+import org.apache.syncope.core.misc.utils.MappingUtils;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.UserDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index 93a0b31..4af649f 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -63,8 +63,8 @@ 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.group.Group;
import org.apache.syncope.common.lib.types.PropagationByResource;
-import org.apache.syncope.core.misc.ConnObjectUtils;
-import org.apache.syncope.core.misc.MappingUtils;
+import org.apache.syncope.core.misc.utils.ConnObjectUtils;
+import org.apache.syncope.core.misc.utils.MappingUtils;
import org.apache.syncope.core.misc.jexl.JexlUtils;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
index af7f0a0..3bb1ed6 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
@@ -24,7 +24,7 @@ import org.apache.commons.collections4.Predicate;
import org.apache.syncope.common.lib.to.AnyTO;
import org.apache.syncope.common.lib.to.RealmTO;
import org.apache.syncope.common.lib.types.ClientExceptionType;
-import org.apache.syncope.core.misc.TemplateUtils;
+import org.apache.syncope.core.misc.utils.TemplateUtils;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
import org.apache.syncope.core.persistence.api.dao.PolicyDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
index 32a095b..e0f8cd8 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/TaskDataBinderImpl.java
@@ -35,7 +35,7 @@ import org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.MatchingRule;
import org.apache.syncope.common.lib.types.TaskType;
import org.apache.syncope.common.lib.types.UnmatchingRule;
-import org.apache.syncope.core.misc.TemplateUtils;
+import org.apache.syncope.core.misc.utils.TemplateUtils;
import org.apache.syncope.core.persistence.api.dao.ExternalResourceDAO;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.dao.TaskExecDAO;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractSchedTaskJobDelegate.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractSchedTaskJobDelegate.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractSchedTaskJobDelegate.java
index 3042239..e3b06b8 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractSchedTaskJobDelegate.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AbstractSchedTaskJobDelegate.java
@@ -21,7 +21,7 @@ package org.apache.syncope.core.provisioning.java.job;
import java.util.Date;
import org.apache.syncope.common.lib.types.AuditElements;
import org.apache.syncope.core.misc.AuditManager;
-import org.apache.syncope.core.misc.ExceptionUtils2;
+import org.apache.syncope.core.misc.utils.ExceptionUtils2;
import org.apache.syncope.core.persistence.api.dao.TaskDAO;
import org.apache.syncope.core.persistence.api.dao.TaskExecDAO;
import org.apache.syncope.core.persistence.api.entity.EntityFactory;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
index 7c6d34c..e3682de 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/TaskJob.java
@@ -21,7 +21,7 @@ package org.apache.syncope.core.provisioning.java.job;
import java.util.Date;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.lang3.ClassUtils;
-import org.apache.syncope.core.misc.FormatUtils;
+import org.apache.syncope.core.misc.utils.FormatUtils;
import org.apache.syncope.core.misc.security.AuthContextUtils;
import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
import org.apache.syncope.core.provisioning.api.job.JobInstanceLoader;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
index e87cd00..d513069 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/AbstractPropagationTaskExecutor.java
@@ -46,9 +46,9 @@ import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
import org.apache.syncope.core.misc.AuditManager;
import org.apache.syncope.core.misc.spring.ApplicationContextProvider;
-import org.apache.syncope.core.misc.ConnObjectUtils;
-import org.apache.syncope.core.misc.ExceptionUtils2;
-import org.apache.syncope.core.misc.MappingUtils;
+import org.apache.syncope.core.misc.utils.ConnObjectUtils;
+import org.apache.syncope.core.misc.utils.ExceptionUtils2;
+import org.apache.syncope.core.misc.utils.MappingUtils;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.VirSchemaDAO;
import org.apache.syncope.core.persistence.api.entity.Any;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
index 22feb44..d635e15 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/DefaultPropagationReporter.java
@@ -24,7 +24,7 @@ import org.apache.syncope.common.lib.to.PropagationStatus;
import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
-import org.apache.syncope.core.misc.ConnObjectUtils;
+import org.apache.syncope.core.misc.utils.ConnObjectUtils;
import org.identityconnectors.framework.common.objects.ConnectorObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
http://git-wip-us.apache.org/repos/asf/syncope/blob/0211410b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java
index a3c4951..90d56ba 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/propagation/PriorityPropagationTaskExecutor.java
@@ -31,20 +31,19 @@ import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
import org.apache.syncope.core.provisioning.api.propagation.PropagationException;
import org.apache.syncope.core.provisioning.api.propagation.PropagationReporter;
-import org.springframework.stereotype.Component;
-@Component
+/**
+ * Sort the given collection by looking at related ExternalResource's priority, then execute.
+ */
public class PriorityPropagationTaskExecutor extends AbstractPropagationTaskExecutor {
- /**
- * Sort the given collection by looking at related ExternalResource's priority, then execute.
- * {@inheritDoc}
- */
@Override
public void execute(final Collection<PropagationTask> tasks, final PropagationReporter reporter) {
- final List<PropagationTask> prioritizedTasks = new ArrayList<>(tasks);
+ List<PropagationTask> prioritizedTasks = new ArrayList<>(tasks);
Collections.sort(prioritizedTasks, new PriorityComparator());
+ LOG.debug("Propagation tasks sorted by priority, before execution: {}", prioritizedTasks);
+
Result result = Result.SUCCESS;
try {