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 {
