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/01/08 14:17:21 UTC
[01/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Repository: syncope
Updated Branches:
refs/heads/2_0_X fc8761c33 -> 99369c311
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/MappingUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/MappingUtil.java b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/MappingUtil.java
new file mode 100644
index 0000000..cb2e140
--- /dev/null
+++ b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/MappingUtil.java
@@ -0,0 +1,736 @@
+/*
+ * 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.server.utils;
+
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.jexl2.JexlContext;
+import org.apache.commons.jexl2.MapContext;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.persistence.api.entity.Attributable;
+import org.apache.syncope.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
+import org.apache.syncope.persistence.api.entity.DerAttr;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.MappingItem;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+import org.apache.syncope.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.persistence.api.entity.PlainSchema;
+import org.apache.syncope.persistence.api.entity.Subject;
+import org.apache.syncope.persistence.api.entity.VirAttr;
+import org.apache.syncope.persistence.api.entity.VirSchema;
+import org.apache.syncope.persistence.api.entity.membership.MDerSchema;
+import org.apache.syncope.persistence.api.entity.membership.MPlainSchema;
+import org.apache.syncope.persistence.api.entity.membership.MVirSchema;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.api.entity.role.RDerSchema;
+import org.apache.syncope.persistence.api.entity.role.RPlainAttrValue;
+import org.apache.syncope.persistence.api.entity.role.RPlainSchema;
+import org.apache.syncope.persistence.api.entity.role.RVirSchema;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.user.UDerSchema;
+import org.apache.syncope.persistence.api.entity.user.UPlainAttrValue;
+import org.apache.syncope.persistence.api.entity.user.UPlainSchema;
+import org.apache.syncope.persistence.api.entity.user.UVirSchema;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.provisioning.api.cache.VirAttrCache;
+import org.apache.syncope.server.security.Encryptor;
+import org.apache.syncope.server.spring.ApplicationContextProvider;
+import org.apache.syncope.server.utils.jexl.JexlUtil;
+import org.identityconnectors.framework.common.FrameworkUtil;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.AttributeBuilder;
+import org.identityconnectors.framework.common.objects.AttributeUtil;
+import org.identityconnectors.framework.common.objects.Name;
+import org.identityconnectors.framework.common.objects.OperationalAttributes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.ConfigurableApplicationContext;
+
+public final class MappingUtil {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(MappingUtil.class);
+
+ private static final Encryptor ENCRYPTOR = Encryptor.getInstance();
+
+ public static <T extends MappingItem> List<T> getMatchingMappingItems(
+ final Collection<T> items, final IntMappingType type) {
+
+ final List<T> result = new ArrayList<>();
+
+ for (T mapItem : items) {
+ if (mapItem.getIntMappingType() == type) {
+ result.add(mapItem);
+ }
+ }
+
+ return result;
+ }
+
+ public static <T extends MappingItem> List<T> getMatchingMappingItems(final Collection<T> items,
+ final String intAttrName, final IntMappingType type) {
+
+ final List<T> result = new ArrayList<>();
+
+ for (T mapItem : items) {
+ if (mapItem.getIntMappingType() == type && intAttrName.equals(mapItem.getIntAttrName())) {
+ result.add(mapItem);
+ }
+ }
+
+ return result;
+ }
+
+ public static <T extends MappingItem> Set<T> getMatchingMappingItems(final Collection<T> mapItems,
+ final String intAttrName) {
+
+ final Set<T> result = new HashSet<>();
+
+ for (T mapItem : mapItems) {
+ if (intAttrName.equals(mapItem.getIntAttrName())) {
+ result.add(mapItem);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Prepare attributes for sending to a connector instance.
+ *
+ * @param attrUtil user / role
+ * @param subject given user / role
+ * @param password clear-text password
+ * @param changePwd whether password should be included for propagation attributes or not
+ * @param vAttrsToBeRemoved virtual attributes to be removed
+ * @param vAttrsToBeUpdated virtual attributes to be added
+ * @param membVAttrsToBeRemoved membership virtual attributes to be removed
+ * @param membVAttrsToBeUpdated membership virtual attributes to be added
+ * @param enable whether user must be enabled or not
+ * @param resource target resource
+ * @return account link + prepared attributes
+ */
+ public static Map.Entry<String, Set<Attribute>> prepareAttributes(
+ final AttributableUtil attrUtil, final Subject<?, ?, ?> subject,
+ final String password,
+ final boolean changePwd,
+ final Set<String> vAttrsToBeRemoved,
+ final Map<String, AttrMod> vAttrsToBeUpdated,
+ final Set<String> membVAttrsToBeRemoved,
+ final Map<String, AttrMod> membVAttrsToBeUpdated,
+ final Boolean enable,
+ final ExternalResource resource) {
+
+ LOG.debug("Preparing resource attributes for {} on resource {} with attributes {}",
+ subject, resource, subject.getPlainAttrs());
+
+ final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
+ final VirAttrCache virAttrCache = context.getBean(VirAttrCache.class);
+ final PasswordGenerator passwordGenerator = context.getBean(PasswordGenerator.class);
+
+ Set<Attribute> attributes = new HashSet<>();
+ String accountId = null;
+
+ for (MappingItem mapping : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+ LOG.debug("Processing schema {}", mapping.getIntAttrName());
+
+ try {
+ if ((attrUtil.getType() == AttributableType.USER
+ && mapping.getIntMappingType() == IntMappingType.UserVirtualSchema)
+ || (attrUtil.getType() == AttributableType.ROLE
+ && mapping.getIntMappingType() == IntMappingType.RoleVirtualSchema)) {
+
+ LOG.debug("Expire entry cache {}-{}", subject.getKey(), mapping.getIntAttrName());
+ virAttrCache.expire(attrUtil.getType(), subject.getKey(), mapping.getIntAttrName());
+ }
+
+ // SYNCOPE-458 expire cache also for membership virtual schemas
+ if (attrUtil.getType() == AttributableType.USER && mapping.getIntMappingType()
+ == IntMappingType.MembershipVirtualSchema && (subject instanceof User)) {
+
+ final User user = (User) subject;
+ for (Membership membership : user.getMemberships()) {
+ LOG.debug("Expire entry cache {}-{} for membership {}", subject.getKey(),
+ mapping.getIntAttrName(), membership);
+ virAttrCache.expire(AttributableType.MEMBERSHIP, membership.getKey(),
+ mapping.getIntAttrName());
+ }
+ }
+
+ Map.Entry<String, Attribute> preparedAttr = prepareAttr(
+ resource, mapping, subject, password, passwordGenerator, vAttrsToBeRemoved, vAttrsToBeUpdated,
+ membVAttrsToBeRemoved, membVAttrsToBeUpdated);
+
+ if (preparedAttr != null && preparedAttr.getKey() != null) {
+ accountId = preparedAttr.getKey();
+ }
+
+ if (preparedAttr != null && preparedAttr.getValue() != null) {
+ Attribute alreadyAdded = AttributeUtil.find(preparedAttr.getValue().getName(), attributes);
+
+ if (alreadyAdded == null) {
+ attributes.add(preparedAttr.getValue());
+ } else {
+ attributes.remove(alreadyAdded);
+
+ Set<Object> values = new HashSet<>(alreadyAdded.getValue());
+ values.addAll(preparedAttr.getValue().getValue());
+
+ attributes.add(AttributeBuilder.build(preparedAttr.getValue().getName(), values));
+ }
+ }
+ } catch (Exception e) {
+ LOG.debug("Attribute '{}' processing failed", mapping.getIntAttrName(), e);
+ }
+ }
+
+ final Attribute accountIdExtAttr =
+ AttributeUtil.find(attrUtil.getAccountIdItem(resource).getExtAttrName(), attributes);
+ if (accountIdExtAttr != null) {
+ attributes.remove(accountIdExtAttr);
+ attributes.add(AttributeBuilder.build(attrUtil.getAccountIdItem(resource).getExtAttrName(), accountId));
+ }
+ attributes.add(MappingUtil.evaluateNAME(subject, resource, accountId));
+
+ if (enable != null) {
+ attributes.add(AttributeBuilder.buildEnabled(enable));
+ }
+ if (!changePwd) {
+ Attribute pwdAttr = AttributeUtil.find(OperationalAttributes.PASSWORD_NAME, attributes);
+ if (pwdAttr != null) {
+ attributes.remove(pwdAttr);
+ }
+ }
+
+ return new AbstractMap.SimpleEntry<>(accountId, attributes);
+ }
+
+ /**
+ * Prepare an attribute to be sent to a connector instance.
+ *
+ * @param resource target resource
+ * @param mapItem mapping item for the given attribute
+ * @param subject given user
+ * @param password clear-text password
+ * @param passwordGenerator password generator
+ * @param vAttrsToBeRemoved virtual attributes to be removed
+ * @param vAttrsToBeUpdated virtual attributes to be added
+ * @return account link + prepared attribute
+ */
+ @SuppressWarnings("unchecked")
+ private static Map.Entry<String, Attribute> prepareAttr(
+ final ExternalResource resource, final MappingItem mapItem,
+ final Subject<?, ?, ?> subject, final String password, final PasswordGenerator passwordGenerator,
+ final Set<String> vAttrsToBeRemoved, final Map<String, AttrMod> vAttrsToBeUpdated,
+ final Set<String> membVAttrsToBeRemoved, final Map<String, AttrMod> membVAttrsToBeUpdated) {
+
+ final List<Attributable<?, ?, ?>> attributables = new ArrayList<>();
+
+ final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
+ final AttributableUtilFactory attrUtilFactory = context.getBean(AttributableUtilFactory.class);
+ final ConnObjectUtil connObjectUtil = context.getBean(ConnObjectUtil.class);
+
+ switch (mapItem.getIntMappingType().getAttributableType()) {
+ case USER:
+ if (subject instanceof User) {
+ attributables.add(subject);
+ }
+ break;
+
+ case ROLE:
+ if (subject instanceof User) {
+ for (Role role : ((User) subject).getRoles()) {
+ connObjectUtil.retrieveVirAttrValues(role, attrUtilFactory.getInstance(role));
+ attributables.add(role);
+ }
+ }
+ if (subject instanceof Role) {
+ attributables.add(subject);
+ }
+ break;
+
+ case MEMBERSHIP:
+ if (subject instanceof User) {
+ attributables.addAll(((User) subject).getMemberships());
+ }
+ break;
+
+ default:
+ }
+
+ List<PlainAttrValue> values = getIntValues(
+ resource, mapItem, attributables, vAttrsToBeRemoved, vAttrsToBeUpdated, membVAttrsToBeRemoved,
+ membVAttrsToBeUpdated);
+
+ PlainSchema schema = null;
+ boolean readOnlyVirSchema = false;
+ AttrSchemaType schemaType;
+ final Map.Entry<String, Attribute> result;
+
+ switch (mapItem.getIntMappingType()) {
+ case UserSchema:
+ case RoleSchema:
+ case MembershipSchema:
+ final PlainSchemaDAO plainSchemaDAO = context.getBean(PlainSchemaDAO.class);
+ schema = plainSchemaDAO.find(mapItem.getIntAttrName(),
+ MappingUtil.getIntMappingTypeClass(mapItem.getIntMappingType()));
+ schemaType = schema == null ? AttrSchemaType.String : schema.getType();
+ break;
+
+ case UserVirtualSchema:
+ case RoleVirtualSchema:
+ case MembershipVirtualSchema:
+ VirSchemaDAO virSchemaDAO = context.getBean(VirSchemaDAO.class);
+ VirSchema virSchema = virSchemaDAO.find(mapItem.getIntAttrName(),
+ MappingUtil.getIntMappingTypeClass(mapItem.getIntMappingType()));
+ readOnlyVirSchema = (virSchema != null && virSchema.isReadonly());
+ schemaType = AttrSchemaType.String;
+ break;
+
+ default:
+ schemaType = AttrSchemaType.String;
+ }
+
+ final String extAttrName = mapItem.getExtAttrName();
+
+ LOG.debug("Define mapping for: "
+ + "\n* ExtAttrName " + extAttrName
+ + "\n* is accountId " + mapItem.isAccountid()
+ + "\n* is password " + (mapItem.isPassword() || mapItem.getIntMappingType() == IntMappingType.Password)
+ + "\n* mandatory condition " + mapItem.getMandatoryCondition()
+ + "\n* Schema " + mapItem.getIntAttrName()
+ + "\n* IntMappingType " + mapItem.getIntMappingType().toString()
+ + "\n* ClassType " + schemaType.getType().getName()
+ + "\n* Values " + values);
+
+ if (readOnlyVirSchema) {
+ result = null;
+ } else {
+ final List<Object> objValues = new ArrayList<>();
+
+ for (PlainAttrValue value : values) {
+ if (FrameworkUtil.isSupportedAttributeType(schemaType.getType())) {
+ objValues.add(value.getValue());
+ } else {
+ objValues.add(value.getValueAsString());
+ }
+ }
+
+ if (mapItem.isAccountid()) {
+ result = new AbstractMap.SimpleEntry<>(objValues.iterator().next().toString(), null);
+ } else if (mapItem.isPassword() && subject instanceof User) {
+ String passwordAttrValue = password;
+ if (StringUtils.isBlank(passwordAttrValue)) {
+ User user = (User) subject;
+ if (user.canDecodePassword()) {
+ try {
+ passwordAttrValue = ENCRYPTOR.decode(user.getPassword(), user.getCipherAlgorithm());
+ } catch (Exception e) {
+ LOG.error("Could not decode password for {}", user, e);
+ }
+ } else if (resource.isRandomPwdIfNotProvided()) {
+ try {
+ passwordAttrValue = passwordGenerator.generate(user);
+ } catch (InvalidPasswordPolicySpecException e) {
+ LOG.error("Could not generate policy-compliant random password for {}", user, e);
+ }
+ }
+ }
+
+ if (passwordAttrValue == null) {
+ result = null;
+ } else {
+ result = new AbstractMap.SimpleEntry<>(
+ null,
+ AttributeBuilder.buildPassword(passwordAttrValue.toCharArray()));
+ }
+ } else {
+ if ((schema != null && schema.isMultivalue()) || attrUtilFactory.getInstance(subject).getType()
+ != mapItem.getIntMappingType().getAttributableType()) {
+
+ result = new AbstractMap.SimpleEntry<>(
+ null,
+ AttributeBuilder.build(extAttrName, objValues));
+ } else {
+ result = new AbstractMap.SimpleEntry<>(
+ null, objValues.isEmpty()
+ ? AttributeBuilder.build(extAttrName)
+ : AttributeBuilder.build(extAttrName, objValues.iterator().next()));
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Build __NAME__ for propagation. First look if there ia a defined accountLink for the given resource (and in this
+ * case evaluate as JEXL); otherwise, take given accountId.
+ *
+ * @param subject given user / role
+ * @param resource target resource
+ * @param accountId accountId
+ * @return the value to be propagated as __NAME__
+ */
+ public static Name evaluateNAME(final Subject<?, ?, ?> subject,
+ final ExternalResource resource, final String accountId) {
+
+ final AttributableUtilFactory attrUtilFactory =
+ ApplicationContextProvider.getApplicationContext().getBean(AttributableUtilFactory.class);
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(subject);
+
+ if (StringUtils.isBlank(accountId)) {
+ // LOG error but avoid to throw exception: leave it to the external resource
+ LOG.error("Missing accountId for '{}': ", resource.getKey());
+ }
+
+ // Evaluate AccountLink expression
+ String evalAccountLink = null;
+ if (StringUtils.isNotBlank(attrUtil.getAccountLink(resource))) {
+ final JexlContext jexlContext = new MapContext();
+ JexlUtil.addFieldsToContext(subject, jexlContext);
+ JexlUtil.addAttrsToContext(subject.getPlainAttrs(), jexlContext);
+ JexlUtil.addDerAttrsToContext(subject.getDerAttrs(), subject.getPlainAttrs(), jexlContext);
+ evalAccountLink = JexlUtil.evaluate(attrUtil.getAccountLink(resource), jexlContext);
+ }
+
+ // If AccountLink evaluates to an empty string, just use the provided AccountId as Name(),
+ // otherwise evaluated AccountLink expression is taken as Name().
+ Name name;
+ if (StringUtils.isBlank(evalAccountLink)) {
+ // add AccountId as __NAME__ attribute ...
+ LOG.debug("Add AccountId [{}] as __NAME__", accountId);
+ name = new Name(accountId);
+ } else {
+ LOG.debug("Add AccountLink [{}] as __NAME__", evalAccountLink);
+ name = new Name(evalAccountLink);
+
+ // AccountId not propagated: it will be used to set the value for __UID__ attribute
+ LOG.debug("AccountId will be used just as __UID__ attribute");
+ }
+
+ return name;
+ }
+
+ private static String getRoleOwnerValue(
+ final ExternalResource resource, final Subject<?, ?, ?> subject) {
+
+ AttributableUtilFactory attrUtilFactory =
+ ApplicationContextProvider.getApplicationContext().getBean(AttributableUtilFactory.class);
+
+ Map.Entry<String, Attribute> preparedAttr = prepareAttr(
+ resource, attrUtilFactory.getInstance(subject).getAccountIdItem(resource), subject, null, null,
+ Collections.<String>emptySet(), Collections.<String, AttrMod>emptyMap(),
+ Collections.<String>emptySet(), Collections.<String, AttrMod>emptyMap());
+ String accountId = preparedAttr.getKey();
+
+ final Name roleOwnerName = evaluateNAME(subject, resource, accountId);
+ return roleOwnerName.getNameValue();
+ }
+
+ /**
+ * Get attribute values.
+ *
+ * @param resource target resource
+ * @param mappingItem mapping item
+ * @param attributables list of attributables
+ * @param vAttrsToBeRemoved virtual attributes to be removed
+ * @param vAttrsToBeUpdated virtual attributes to be added
+ * @param membVAttrsToBeRemoved membership virtual attributes to be removed
+ * @param membVAttrsToBeUpdated membership virtual attributes to be added
+ * @return attribute values.
+ */
+ public static List<PlainAttrValue> getIntValues(final ExternalResource resource,
+ final MappingItem mappingItem, final List<Attributable<?, ?, ?>> attributables,
+ final Set<String> vAttrsToBeRemoved, final Map<String, AttrMod> vAttrsToBeUpdated,
+ final Set<String> membVAttrsToBeRemoved, final Map<String, AttrMod> membVAttrsToBeUpdated) {
+
+ LOG.debug("Get attributes for '{}' and mapping type '{}'", attributables, mappingItem.getIntMappingType());
+
+ final EntityFactory entityFactory =
+ ApplicationContextProvider.getApplicationContext().getBean(EntityFactory.class);
+ List<PlainAttrValue> values = new ArrayList<>();
+ PlainAttrValue attrValue;
+ switch (mappingItem.getIntMappingType()) {
+ case UserSchema:
+ case RoleSchema:
+ case MembershipSchema:
+ for (Attributable<?, ?, ?> attributable : attributables) {
+ final PlainAttr attr = attributable.getPlainAttr(mappingItem.getIntAttrName());
+ if (attr != null) {
+ if (attr.getUniqueValue() != null) {
+ values.add(attr.getUniqueValue());
+ } else if (attr.getValues() != null) {
+ values.addAll(attr.getValues());
+ }
+ }
+
+ LOG.debug("Retrieved attribute {}"
+ + "\n* IntAttrName {}"
+ + "\n* IntMappingType {}"
+ + "\n* Attribute values {}",
+ attr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+ }
+
+ break;
+
+ case UserVirtualSchema:
+ case RoleVirtualSchema:
+ for (Attributable<?, ?, ?> attributable : attributables) {
+ VirAttr virAttr = attributable.getVirAttr(mappingItem.getIntAttrName());
+ if (virAttr != null) {
+ if (vAttrsToBeRemoved != null && vAttrsToBeUpdated != null) {
+ if (vAttrsToBeUpdated.containsKey(mappingItem.getIntAttrName())) {
+ virAttr.getValues().clear();
+ virAttr.getValues().addAll(
+ vAttrsToBeUpdated.get(mappingItem.getIntAttrName()).getValuesToBeAdded());
+ } else if (vAttrsToBeRemoved.contains(mappingItem.getIntAttrName())) {
+ virAttr.getValues().clear();
+ } else {
+ throw new IllegalArgumentException("Don't need to update virtual attribute '"
+ + mappingItem.getIntAttrName() + "'");
+ }
+ }
+ if (virAttr.getValues() != null) {
+ for (String value : virAttr.getValues()) {
+ attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+ attrValue.setStringValue(value);
+ values.add(attrValue);
+ }
+ }
+ }
+
+ LOG.debug("Retrieved {} virtual attribute {}"
+ + "\n* IntAttrName {}"
+ + "\n* IntMappingType {}"
+ + "\n* Attribute values {}",
+ attributable.getClass().getSimpleName(),
+ virAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+ }
+ break;
+
+ case MembershipVirtualSchema:
+ for (Attributable<?, ?, ?> attributable : attributables) {
+ VirAttr virAttr = attributable.getVirAttr(mappingItem.getIntAttrName());
+ if (virAttr != null) {
+ if (membVAttrsToBeRemoved != null && membVAttrsToBeUpdated != null) {
+ if (membVAttrsToBeUpdated.containsKey(mappingItem.getIntAttrName())) {
+ virAttr.getValues().clear();
+ virAttr.getValues().addAll(
+ membVAttrsToBeUpdated.get(mappingItem.getIntAttrName()).getValuesToBeAdded());
+ } else if (membVAttrsToBeRemoved.contains(mappingItem.getIntAttrName())) {
+ virAttr.getValues().clear();
+ } else {
+ throw new IllegalArgumentException("Don't need to update membership virtual attribute '"
+ + mappingItem.getIntAttrName() + "'");
+ }
+ }
+ if (virAttr.getValues() != null) {
+ for (String value : virAttr.getValues()) {
+ attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+ attrValue.setStringValue(value);
+ values.add(attrValue);
+ }
+ }
+ }
+
+ LOG.debug("Retrieved {} virtual attribute {}"
+ + "\n* IntAttrName {}"
+ + "\n* IntMappingType {}"
+ + "\n* Attribute values {}",
+ attributable.getClass().getSimpleName(),
+ virAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+ }
+ break;
+
+ case UserDerivedSchema:
+ case RoleDerivedSchema:
+ case MembershipDerivedSchema:
+ for (Attributable<?, ?, ?> attributable : attributables) {
+ DerAttr derAttr = attributable.getDerAttr(mappingItem.getIntAttrName());
+ if (derAttr != null) {
+ attrValue = attributable instanceof Role
+ ? entityFactory.newEntity(RPlainAttrValue.class)
+ : entityFactory.newEntity(UPlainAttrValue.class);
+ attrValue.setStringValue(derAttr.getValue(attributable.getPlainAttrs()));
+ values.add(attrValue);
+ }
+
+ LOG.debug("Retrieved attribute {}"
+ + "\n* IntAttrName {}"
+ + "\n* IntMappingType {}"
+ + "\n* Attribute values {}",
+ derAttr, mappingItem.getIntAttrName(), mappingItem.getIntMappingType(), values);
+ }
+ break;
+
+ case UserId:
+ case RoleId:
+ case MembershipId:
+ for (Attributable<?, ?, ?> attributable : attributables) {
+ attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+ attrValue.setStringValue(attributable.getKey().toString());
+ values.add(attrValue);
+ }
+ break;
+
+ case Username:
+ for (Attributable<?, ?, ?> attributable : attributables) {
+ if (attributable instanceof User) {
+ attrValue = entityFactory.newEntity(UPlainAttrValue.class);
+ attrValue.setStringValue(((User) attributable).getUsername());
+ values.add(attrValue);
+ }
+ }
+ break;
+
+ case RoleName:
+ for (Attributable<?, ?, ?> attributable : attributables) {
+ if (attributable instanceof Role) {
+ attrValue = entityFactory.newEntity(RPlainAttrValue.class);
+ attrValue.setStringValue(((Role) attributable).getName());
+ values.add(attrValue);
+ }
+ }
+ break;
+
+ case RoleOwnerSchema:
+ for (Attributable<?, ?, ?> attributable : attributables) {
+ if (attributable instanceof Role) {
+ Role role = (Role) attributable;
+ String roleOwnerValue = null;
+ if (role.getUserOwner() != null && resource.getUmapping() != null) {
+ roleOwnerValue = getRoleOwnerValue(resource, role.getUserOwner());
+ }
+ if (role.getRoleOwner() != null && resource.getRmapping() != null) {
+ roleOwnerValue = getRoleOwnerValue(resource, role.getRoleOwner());
+ }
+
+ if (StringUtils.isNotBlank(roleOwnerValue)) {
+ attrValue = entityFactory.newEntity(RPlainAttrValue.class);
+ attrValue.setStringValue(roleOwnerValue);
+ values.add(attrValue);
+ }
+ }
+ }
+ break;
+
+ default:
+ }
+
+ LOG.debug("Retrieved values '{}'", values);
+
+ return values;
+ }
+
+ /**
+ * Get accountId internal value.
+ *
+ * @param attributable attributable
+ * @param accountIdItem accountId mapping item
+ * @param resource external resource
+ * @return accountId internal value
+ */
+ public static String getAccountIdValue(final Attributable<?, ?, ?> attributable,
+ final ExternalResource resource, final MappingItem accountIdItem) {
+
+ List<PlainAttrValue> values = getIntValues(resource, accountIdItem,
+ Collections.<Attributable<?, ?, ?>>singletonList(attributable), null, null, null, null);
+ return values == null || values.isEmpty()
+ ? null
+ : values.get(0).getValueAsString();
+ }
+
+ /**
+ * For given source mapping type, return the corresponding Class object.
+ *
+ * @param intMappingType source mapping type
+ * @return corresponding Class object, if any (can be null)
+ */
+ @SuppressWarnings("rawtypes")
+ public static Class getIntMappingTypeClass(final IntMappingType intMappingType) {
+ Class result;
+
+ switch (intMappingType) {
+ case UserSchema:
+ result = UPlainSchema.class;
+ break;
+
+ case RoleSchema:
+ result = RPlainSchema.class;
+ break;
+
+ case MembershipSchema:
+ result = MPlainSchema.class;
+ break;
+
+ case UserDerivedSchema:
+ result = UDerSchema.class;
+ break;
+
+ case RoleDerivedSchema:
+ result = RDerSchema.class;
+ break;
+
+ case MembershipDerivedSchema:
+ result = MDerSchema.class;
+ break;
+
+ case UserVirtualSchema:
+ result = UVirSchema.class;
+ break;
+
+ case RoleVirtualSchema:
+ result = RVirSchema.class;
+ break;
+
+ case MembershipVirtualSchema:
+ result = MVirSchema.class;
+ break;
+
+ default:
+ result = null;
+ }
+
+ return result;
+ }
+
+ /**
+ * Private default constructor, for static-only classes.
+ */
+ private MappingUtil() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/PasswordGenerator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/PasswordGenerator.java b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/PasswordGenerator.java
new file mode 100644
index 0000000..9ad4ad0
--- /dev/null
+++ b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/PasswordGenerator.java
@@ -0,0 +1,320 @@
+/*
+ * 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.server.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.types.PasswordPolicySpec;
+import org.apache.syncope.persistence.api.dao.PolicyDAO;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.server.utils.policy.PolicyPattern;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * Generate random passwords according to given policies.
+ *
+ * @see PasswordPolicy
+ */
+@Component
+public class PasswordGenerator {
+
+ private static final char[] SPECIAL_CHARS = { '!', '£', '%', '&', '(', ')', '?', '#', '$' };
+
+ @Autowired
+ private PolicyDAO policyDAO;
+
+ public String generate(final List<PasswordPolicySpec> ppSpecs)
+ throws InvalidPasswordPolicySpecException {
+
+ PasswordPolicySpec policySpec = merge(ppSpecs);
+
+ check(policySpec);
+
+ return generate(policySpec);
+ }
+
+ public String generate(final User user)
+ throws InvalidPasswordPolicySpecException {
+
+ List<PasswordPolicySpec> ppSpecs = new ArrayList<PasswordPolicySpec>();
+
+ PasswordPolicy globalPP = policyDAO.getGlobalPasswordPolicy();
+ if (globalPP != null && globalPP.getSpecification(PasswordPolicySpec.class) != null) {
+ ppSpecs.add(globalPP.getSpecification(PasswordPolicySpec.class));
+ }
+
+ for (Role role : user.getRoles()) {
+ if (role.getPasswordPolicy() != null
+ && role.getPasswordPolicy().getSpecification(PasswordPolicySpec.class) != null) {
+
+ ppSpecs.add(role.getPasswordPolicy().getSpecification(PasswordPolicySpec.class));
+ }
+ }
+
+ for (ExternalResource resource : user.getResources()) {
+ if (resource.getPasswordPolicy() != null
+ && resource.getPasswordPolicy().getSpecification(PasswordPolicySpec.class) != null) {
+
+ ppSpecs.add(resource.getPasswordPolicy().getSpecification(PasswordPolicySpec.class));
+ }
+ }
+
+ PasswordPolicySpec policySpec = merge(ppSpecs);
+ check(policySpec);
+ return generate(policySpec);
+ }
+
+ private PasswordPolicySpec merge(final List<PasswordPolicySpec> ppSpecs) {
+ PasswordPolicySpec fpps = new PasswordPolicySpec();
+ fpps.setMinLength(0);
+ fpps.setMaxLength(1000);
+
+ for (PasswordPolicySpec policySpec : ppSpecs) {
+ if (policySpec.getMinLength() > fpps.getMinLength()) {
+ fpps.setMinLength(policySpec.getMinLength());
+ }
+
+ if ((policySpec.getMaxLength() != 0) && ((policySpec.getMaxLength() < fpps.getMaxLength()))) {
+ fpps.setMaxLength(policySpec.getMaxLength());
+ }
+ fpps.getPrefixesNotPermitted().addAll(policySpec.getPrefixesNotPermitted());
+ fpps.getSuffixesNotPermitted().addAll(policySpec.getSuffixesNotPermitted());
+
+ if (!fpps.isNonAlphanumericRequired()) {
+ fpps.setNonAlphanumericRequired(policySpec.isNonAlphanumericRequired());
+ }
+
+ if (!fpps.isAlphanumericRequired()) {
+ fpps.setAlphanumericRequired(policySpec.isAlphanumericRequired());
+ }
+ if (!fpps.isDigitRequired()) {
+ fpps.setDigitRequired(policySpec.isDigitRequired());
+ }
+
+ if (!fpps.isLowercaseRequired()) {
+ fpps.setLowercaseRequired(policySpec.isLowercaseRequired());
+ }
+ if (!fpps.isUppercaseRequired()) {
+ fpps.setUppercaseRequired(policySpec.isUppercaseRequired());
+ }
+ if (!fpps.isMustStartWithDigit()) {
+ fpps.setMustStartWithDigit(policySpec.isMustStartWithDigit());
+ }
+ if (!fpps.isMustntStartWithDigit()) {
+ fpps.setMustntStartWithDigit(policySpec.isMustntStartWithDigit());
+ }
+ if (!fpps.isMustEndWithDigit()) {
+ fpps.setMustEndWithDigit(policySpec.isMustEndWithDigit());
+ }
+ if (fpps.isMustntEndWithDigit()) {
+ fpps.setMustntEndWithDigit(policySpec.isMustntEndWithDigit());
+ }
+ if (!fpps.isMustStartWithAlpha()) {
+ fpps.setMustStartWithAlpha(policySpec.isMustStartWithAlpha());
+ }
+ if (!fpps.isMustntStartWithAlpha()) {
+ fpps.setMustntStartWithAlpha(policySpec.isMustntStartWithAlpha());
+ }
+ if (!fpps.isMustStartWithNonAlpha()) {
+ fpps.setMustStartWithNonAlpha(policySpec.isMustStartWithNonAlpha());
+ }
+ if (!fpps.isMustntStartWithNonAlpha()) {
+ fpps.setMustntStartWithNonAlpha(policySpec.isMustntStartWithNonAlpha());
+ }
+ if (!fpps.isMustEndWithNonAlpha()) {
+ fpps.setMustEndWithNonAlpha(policySpec.isMustEndWithNonAlpha());
+ }
+ if (!fpps.isMustntEndWithNonAlpha()) {
+ fpps.setMustntEndWithNonAlpha(policySpec.isMustntEndWithNonAlpha());
+ }
+ if (!fpps.isMustEndWithAlpha()) {
+ fpps.setMustEndWithAlpha(policySpec.isMustEndWithAlpha());
+ }
+ if (!fpps.isMustntEndWithAlpha()) {
+ fpps.setMustntEndWithAlpha(policySpec.isMustntEndWithAlpha());
+ }
+ }
+ return fpps;
+ }
+
+ private void check(final PasswordPolicySpec policySpec)
+ throws InvalidPasswordPolicySpecException {
+
+ if (policySpec.getMinLength() == 0) {
+ throw new InvalidPasswordPolicySpecException("Minimum length is zero");
+ }
+ if (policySpec.isMustEndWithAlpha() && policySpec.isMustntEndWithAlpha()) {
+ throw new InvalidPasswordPolicySpecException(
+ "mustEndWithAlpha and mustntEndWithAlpha are both true");
+ }
+ if (policySpec.isMustEndWithAlpha() && policySpec.isMustEndWithDigit()) {
+ throw new InvalidPasswordPolicySpecException(
+ "mustEndWithAlpha and mustEndWithDigit are both true");
+ }
+ if (policySpec.isMustEndWithDigit() && policySpec.isMustntEndWithDigit()) {
+ throw new InvalidPasswordPolicySpecException(
+ "mustEndWithDigit and mustntEndWithDigit are both true");
+ }
+ if (policySpec.isMustEndWithNonAlpha() && policySpec.isMustntEndWithNonAlpha()) {
+ throw new InvalidPasswordPolicySpecException(
+ "mustEndWithNonAlpha and mustntEndWithNonAlpha are both true");
+ }
+ if (policySpec.isMustStartWithAlpha() && policySpec.isMustntStartWithAlpha()) {
+ throw new InvalidPasswordPolicySpecException(
+ "mustStartWithAlpha and mustntStartWithAlpha are both true");
+ }
+ if (policySpec.isMustStartWithAlpha() && policySpec.isMustStartWithDigit()) {
+ throw new InvalidPasswordPolicySpecException(
+ "mustStartWithAlpha and mustStartWithDigit are both true");
+ }
+ if (policySpec.isMustStartWithDigit() && policySpec.isMustntStartWithDigit()) {
+ throw new InvalidPasswordPolicySpecException(
+ "mustStartWithDigit and mustntStartWithDigit are both true");
+ }
+ if (policySpec.isMustStartWithNonAlpha() && policySpec.isMustntStartWithNonAlpha()) {
+ throw new InvalidPasswordPolicySpecException(
+ "mustStartWithNonAlpha and mustntStartWithNonAlpha are both true");
+ }
+ if (policySpec.getMinLength() > policySpec.getMaxLength()) {
+ throw new InvalidPasswordPolicySpecException("Minimun length (" + policySpec.getMinLength() + ")"
+ + "is greater than maximum length (" + policySpec.getMaxLength() + ")");
+ }
+ }
+
+ private String generate(final PasswordPolicySpec policySpec) {
+ String[] generatedPassword = new String[policySpec.getMinLength()];
+
+ for (int i = 0; i < generatedPassword.length; i++) {
+ generatedPassword[i] = "";
+ }
+
+ checkStartChar(generatedPassword, policySpec);
+
+ checkEndChar(generatedPassword, policySpec);
+
+ checkRequired(generatedPassword, policySpec);
+
+ //filled empty chars
+ for (int firstEmptyChar = firstEmptyChar(generatedPassword);
+ firstEmptyChar < generatedPassword.length - 1; firstEmptyChar++) {
+ generatedPassword[firstEmptyChar] = SecureRandomUtil.generateRandomLetter();
+ }
+
+ checkPrefixAndSuffix(generatedPassword, policySpec);
+
+ return StringUtils.join(generatedPassword);
+ }
+
+ private void checkStartChar(final String[] generatedPassword, final PasswordPolicySpec policySpec) {
+ if (policySpec.isMustStartWithAlpha()) {
+ generatedPassword[0] = SecureRandomUtil.generateRandomLetter();
+ }
+ if (policySpec.isMustStartWithNonAlpha() || policySpec.isMustStartWithDigit()) {
+ generatedPassword[0] = SecureRandomUtil.generateRandomNumber();
+ }
+ if (policySpec.isMustntStartWithAlpha()) {
+ generatedPassword[0] = SecureRandomUtil.generateRandomNumber();
+
+ }
+ if (policySpec.isMustntStartWithDigit()) {
+ generatedPassword[0] = SecureRandomUtil.generateRandomLetter();
+
+ }
+ if (policySpec.isMustntStartWithNonAlpha()) {
+ generatedPassword[0] = SecureRandomUtil.generateRandomLetter();
+
+ }
+ }
+
+ private void checkEndChar(final String[] generatedPassword, final PasswordPolicySpec policySpec) {
+ if (policySpec.isMustEndWithAlpha()) {
+ generatedPassword[policySpec.getMinLength() - 1] = SecureRandomUtil.generateRandomLetter();
+ }
+ if (policySpec.isMustEndWithNonAlpha() || policySpec.isMustEndWithDigit()) {
+ generatedPassword[policySpec.getMinLength() - 1] = SecureRandomUtil.generateRandomNumber();
+ }
+
+ if (policySpec.isMustntEndWithAlpha()) {
+ generatedPassword[policySpec.getMinLength() - 1] = SecureRandomUtil.generateRandomNumber();
+ }
+ if (policySpec.isMustntEndWithDigit()) {
+ generatedPassword[policySpec.getMinLength() - 1] = SecureRandomUtil.generateRandomLetter();
+ }
+ if (policySpec.isMustntEndWithNonAlpha()) {
+ generatedPassword[policySpec.getMinLength() - 1] = SecureRandomUtil.generateRandomLetter();
+
+ }
+ }
+
+ private int firstEmptyChar(final String[] generatedPStrings) {
+ int index = 0;
+ while (!generatedPStrings[index].isEmpty()) {
+ index++;
+ }
+ return index;
+ }
+
+ private void checkRequired(final String[] generatedPassword, final PasswordPolicySpec policySpec) {
+ if (policySpec.isDigitRequired()
+ && !PolicyPattern.DIGIT.matcher(StringUtils.join(generatedPassword)).matches()) {
+
+ generatedPassword[firstEmptyChar(generatedPassword)] = SecureRandomUtil.generateRandomNumber();
+ }
+
+ if (policySpec.isUppercaseRequired()
+ && !PolicyPattern.ALPHA_UPPERCASE.matcher(StringUtils.join(generatedPassword)).matches()) {
+
+ generatedPassword[firstEmptyChar(generatedPassword)] = SecureRandomUtil.generateRandomLetter().toUpperCase();
+ }
+
+ if (policySpec.isLowercaseRequired()
+ && !PolicyPattern.ALPHA_LOWERCASE.matcher(StringUtils.join(generatedPassword)).matches()) {
+
+ generatedPassword[firstEmptyChar(generatedPassword)] = SecureRandomUtil.generateRandomLetter().toLowerCase();
+ }
+
+ if (policySpec.isNonAlphanumericRequired()
+ && !PolicyPattern.NON_ALPHANUMERIC.matcher(StringUtils.join(generatedPassword)).matches()) {
+
+ generatedPassword[firstEmptyChar(generatedPassword)] =
+ SecureRandomUtil.generateRandomSpecialCharacter(SPECIAL_CHARS);
+ }
+ }
+
+ private void checkPrefixAndSuffix(final String[] generatedPassword, final PasswordPolicySpec policySpec) {
+ for (String prefix : policySpec.getPrefixesNotPermitted()) {
+ if (StringUtils.join(generatedPassword).startsWith(prefix)) {
+ checkStartChar(generatedPassword, policySpec);
+ }
+ }
+
+ for (String suffix : policySpec.getSuffixesNotPermitted()) {
+ if (StringUtils.join(generatedPassword).endsWith(suffix)) {
+ checkEndChar(generatedPassword, policySpec);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/SecureRandomUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/SecureRandomUtil.java b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/SecureRandomUtil.java
new file mode 100644
index 0000000..50d3259
--- /dev/null
+++ b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/SecureRandomUtil.java
@@ -0,0 +1,48 @@
+/*
+ * 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.server.utils;
+
+import java.security.SecureRandom;
+
+import org.apache.commons.lang3.RandomStringUtils;
+
+public final class SecureRandomUtil {
+
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ public static String generateRandomPassword(final int tokenLength) {
+ return RandomStringUtils.random(tokenLength, 0, 0, true, false, null, RANDOM);
+ }
+
+ public static String generateRandomLetter() {
+ return RandomStringUtils.random(1, 0, 0, true, false, null, RANDOM);
+ }
+
+ public static String generateRandomNumber() {
+ return RandomStringUtils.random(1, 0, 0, false, true, null, RANDOM);
+ }
+
+ public static String generateRandomSpecialCharacter(char[] characters) {
+ return RandomStringUtils.random(1, 0, 0, false, false, characters, RANDOM);
+ }
+
+ private SecureRandomUtil() {
+ // private constructor for static utility class
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/URIUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/URIUtil.java b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/URIUtil.java
deleted file mode 100644
index 903b8ca..0000000
--- a/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/URIUtil.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.server.utils;
-
-import java.io.File;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-
-public final class URIUtil {
-
- private URIUtil() {
- // empty constructor for static utility class
- }
-
- /**
- * Build a valid URI out of the given location.
- * Only "file", "connid" and "connids" schemes are allowed.
- * For "file", invalid characters are handled via intermediate transformation into URL.
- *
- * @param location the candidate location for URI
- * @return valid URI for the given location
- * @throws MalformedURLException if the intermediate URL is not valid
- * @throws URISyntaxException if the given location does not correspond to a valid URI
- */
- public static URI buildForConnId(final String location) throws MalformedURLException, URISyntaxException {
- final String candidate = location.trim();
-
- if (!candidate.startsWith("file:")
- && !candidate.startsWith("connid:") && !candidate.startsWith("connids:")) {
-
- throw new IllegalArgumentException(candidate + " is not a valid URI for file or connid(s) schemes");
- }
-
- URI uri;
- if (candidate.startsWith("file:")) {
- uri = new File(new URL(candidate).getFile()).getAbsoluteFile().toURI();
- } else {
- uri = new URI(candidate);
- }
-
- return uri;
- }
-}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/serialization/UnwrappedObjectMapper.java
----------------------------------------------------------------------
diff --git a/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/serialization/UnwrappedObjectMapper.java b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/serialization/UnwrappedObjectMapper.java
new file mode 100644
index 0000000..29bce71
--- /dev/null
+++ b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/serialization/UnwrappedObjectMapper.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.server.utils.serialization;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.util.Map;
+
+/**
+ * Jackson ObjectMapper that unwraps singleton map values and enable default
+ * typing for handling abstract types serialization.
+ */
+public class UnwrappedObjectMapper extends ObjectMapper {
+
+ private static final long serialVersionUID = -317191546835195103L;
+
+ /**
+ * Unwraps the given value if it implements the Map interface and contains
+ * only a single entry. Otherwise the value is returned unmodified.
+ *
+ * @param value the potential Map to unwrap
+ * @return the unwrapped map or the original value
+ */
+ private Object unwrapMap(final Object value) {
+ if (value instanceof Map) {
+ Map<?, ?> map = (Map<?, ?>) value;
+ if (map.size() == 1) {
+ return map.values().iterator().next();
+ }
+ }
+
+ return value;
+ }
+
+ @Override
+ public void writeValue(final JsonGenerator jgen, final Object value)
+ throws IOException, JsonGenerationException, JsonMappingException {
+
+ super.writeValue(jgen, unwrapMap(value));
+ }
+
+ @Override
+ public void writeValue(final File resultFile, final Object value)
+ throws IOException, JsonGenerationException, JsonMappingException {
+
+ super.writeValue(resultFile, unwrapMap(value));
+ }
+
+ @Override
+ public void writeValue(final OutputStream out, final Object value)
+ throws IOException, JsonGenerationException, JsonMappingException {
+
+ super.writeValue(out, unwrapMap(value));
+ }
+
+ @Override
+ public void writeValue(final Writer w, final Object value)
+ throws IOException, JsonGenerationException, JsonMappingException {
+
+ super.writeValue(w, unwrapMap(value));
+ }
+
+ @Override
+ public byte[] writeValueAsBytes(final Object value) throws JsonProcessingException {
+ return super.writeValueAsBytes(unwrapMap(value));
+ }
+
+ @Override
+ public String writeValueAsString(final Object value) throws JsonProcessingException {
+ return super.writeValueAsString(unwrapMap(value));
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/workflow-api/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/workflow-api/pom.xml b/syncope620/server/workflow-api/pom.xml
new file mode 100644
index 0000000..af7bed8
--- /dev/null
+++ b/syncope620/server/workflow-api/pom.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.syncope</groupId>
+ <artifactId>syncope-server</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </parent>
+
+ <name>Apache Syncope Server Workflow API</name>
+ <description>Apache Syncope Server Workflow API</description>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-workflow-api</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-provisioning-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/RoleWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/RoleWorkflowAdapter.java b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/RoleWorkflowAdapter.java
new file mode 100644
index 0000000..76e0798
--- /dev/null
+++ b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/RoleWorkflowAdapter.java
@@ -0,0 +1,71 @@
+/*
+ * 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.server.workflow.api;
+
+import org.apache.syncope.provisioning.api.WorkflowResult;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+
+/**
+ * Interface for calling underlying workflow implementations.
+ */
+public interface RoleWorkflowAdapter extends WorkflowAdapter {
+
+ /**
+ * Create a role.
+ *
+ * @param roleTO role to be created and wether to propagate it as active
+ * @return role just created
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Long> create(RoleTO roleTO) throws WorkflowException;
+
+ /**
+ * Execute a task on a role.
+ *
+ * @param roleTO role to be subject to task
+ * @param taskId to be executed
+ * @return role just updated
+ * @throws NotFoundException role not found exception
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Long> execute(RoleTO roleTO, String taskId)
+ throws NotFoundException, WorkflowException;
+
+ /**
+ * Update a role.
+ *
+ * @param roleMod modification set to be performed
+ * @return role just updated and propagations to be performed
+ * @throws NotFoundException role not found exception
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Long> update(RoleMod roleMod)
+ throws NotFoundException, WorkflowException;
+
+ /**
+ * Delete a role.
+ *
+ * @param roleKey role to be deleted
+ * @throws NotFoundException role not found exception
+ * @throws WorkflowException workflow exception
+ */
+ void delete(Long roleKey) throws NotFoundException, WorkflowException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/UserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/UserWorkflowAdapter.java b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/UserWorkflowAdapter.java
new file mode 100644
index 0000000..1c521f1
--- /dev/null
+++ b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/UserWorkflowAdapter.java
@@ -0,0 +1,151 @@
+/*
+ * 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.server.workflow.api;
+
+import org.apache.syncope.provisioning.api.WorkflowResult;
+import java.util.Map;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.persistence.api.entity.user.User;
+
+/**
+ * Interface for calling underlying workflow implementations.
+ */
+public interface UserWorkflowAdapter extends WorkflowAdapter {
+
+ /**
+ * Create an user.
+ *
+ * @param userTO user to be created and whether to propagate it as active
+ * @param storePassword whether password shall be stored into the internal storage
+ * @return user just created
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Map.Entry<Long, Boolean>> create(UserTO userTO, boolean storePassword) throws
+ WorkflowException;
+
+ /**
+ * Create an user, optionally disabling password policy check.
+ *
+ * @param userTO user to be created and whether to propagate it as active
+ * @param disablePwdPolicyCheck disable password policy check?
+ * @param storePassword whether password shall be stored into the internal storage
+ * @return user just created
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Map.Entry<Long, Boolean>> create(UserTO userTO, boolean disablePwdPolicyCheck,
+ boolean storePassword) throws WorkflowException;
+
+ /**
+ * Create an user, optionally disabling password policy check.
+ *
+ * @param userTO user to be created and whether to propagate it as active
+ * @param disablePwdPolicyCheck disable password policy check?
+ * @param enabled specify true/false to force active/supended status
+ * @param storePassword whether password shall be stored into the internal storage
+ * @return user just created
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Map.Entry<Long, Boolean>> create(UserTO userTO, boolean disablePwdPolicyCheck, final Boolean enabled,
+ boolean storePassword) throws WorkflowException;
+
+ /**
+ * Execute a task on an user.
+ *
+ * @param userTO user to be subject to task
+ * @param taskId to be executed
+ * @return user just updated
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Long> execute(UserTO userTO, String taskId) throws WorkflowException;
+
+ /**
+ * Activate an user.
+ *
+ * @param userKey user to be activated
+ * @param token to be verified for activation
+ * @return user just updated
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Long> activate(Long userKey, String token) throws WorkflowException;
+
+ /**
+ * Update an user.
+ *
+ * @param userMod modification set to be performed
+ * @return user just updated and propagations to be performed
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Map.Entry<UserMod, Boolean>> update(UserMod userMod)
+ throws WorkflowException;
+
+ /**
+ * Suspend an user.
+ *
+ * @param userKey user to be suspended
+ * @return user just suspended
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Long> suspend(Long userKey) throws WorkflowException;
+
+ /**
+ * Suspend an user.
+ *
+ * @param user to be suspended
+ * @return user just suspended
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Long> suspend(User user) throws WorkflowException;
+
+ /**
+ * Reactivate an user.
+ *
+ * @param userKey user to be reactivated
+ * @return user just reactivated
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<Long> reactivate(Long userKey) throws WorkflowException;
+
+ /**
+ * Request password reset for an user.
+ *
+ * @param userKey user requesting password reset
+ * @throws WorkflowException workflow exception
+ */
+ void requestPasswordReset(Long userKey) throws WorkflowException;
+
+ /**
+ * Confirm password reset for an user.
+ *
+ * @param userKey user confirming password reset
+ * @param token security token
+ * @param password new password value
+ * @throws WorkflowException workflow exception
+ */
+ void confirmPasswordReset(Long userKey, String token, String password)
+ throws WorkflowException;
+
+ /**
+ * Delete an user.
+ *
+ * @param userKey user to be deleted
+ * @throws WorkflowException workflow exception
+ */
+ void delete(Long userKey) throws WorkflowException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowAdapter.java b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowAdapter.java
new file mode 100644
index 0000000..0b50031
--- /dev/null
+++ b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowAdapter.java
@@ -0,0 +1,111 @@
+/*
+ * 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.server.workflow.api;
+
+import org.apache.syncope.provisioning.api.WorkflowResult;
+import java.io.OutputStream;
+import java.util.List;
+import org.apache.syncope.common.lib.mod.AbstractAttributableMod;
+import org.apache.syncope.common.lib.to.WorkflowFormTO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+
+public interface WorkflowAdapter {
+
+ /**
+ * Give the class to be instantiated and invoked by SpringContextInitializer for loading anything needed by this
+ * adapter.
+ *
+ * @return null if no init is needed or the WorkflowLoader class for handling initialization
+ * @see org.apache.syncope.core.init.SpringContextInitializer
+ */
+ Class<? extends WorkflowInstanceLoader> getLoaderClass();
+
+ /**
+ * Export workflow definition.
+ *
+ * @param format export format
+ * @param os export stream
+ * @throws WorkflowException workflow exception
+ */
+ void exportDefinition(WorkflowDefinitionFormat format, OutputStream os) throws WorkflowException;
+
+ /**
+ * Export workflow graphical representation (if available).
+ *
+ * @param os export stream
+ * @throws WorkflowException workflow exception
+ */
+ void exportDiagram(OutputStream os) throws WorkflowException;
+
+ /**
+ * Update workflow definition.
+ *
+ * @param format import format
+ * @param definition definition
+ * @throws WorkflowException workflow exception
+ */
+ void importDefinition(WorkflowDefinitionFormat format, String definition) throws WorkflowException;
+
+ /**
+ * Get all defined forms for current workflow process instances.
+ *
+ * @return list of defined forms
+ */
+ List<WorkflowFormTO> getForms();
+
+ /**
+ * Gets all forms with the given name for the given workflowId(include historical forms).
+ *
+ * @param workflowId workflow id.
+ * @param name form name.
+ * @return forms (if present), otherwise an empty list.
+ */
+ List<WorkflowFormTO> getForms(String workflowId, String name);
+
+ /**
+ * Get form for given workflowId (if present).
+ *
+ * @param workflowId workflow id
+ * @return form (if present), otherwise null
+ * @throws NotFoundException definition not found exception
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowFormTO getForm(String workflowId) throws NotFoundException, WorkflowException;
+
+ /**
+ * Claim a form for a given user.
+ *
+ * @param taskId Workflow task to which the form is associated
+ * @return updated form
+ * @throws NotFoundException not found exception
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowFormTO claimForm(String taskId) throws NotFoundException, WorkflowException;
+
+ /**
+ * Submit a form.
+ *
+ * @param form to be submitted
+ * @return user updated by this form submit
+ * @throws NotFoundException not found exception
+ * @throws WorkflowException workflow exception
+ */
+ WorkflowResult<? extends AbstractAttributableMod> submitForm(WorkflowFormTO form)
+ throws NotFoundException, WorkflowException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowDefinitionFormat.java
----------------------------------------------------------------------
diff --git a/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowDefinitionFormat.java b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowDefinitionFormat.java
new file mode 100644
index 0000000..41ffe1d
--- /dev/null
+++ b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowDefinitionFormat.java
@@ -0,0 +1,29 @@
+/*
+ * 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.server.workflow.api;
+
+/**
+ * Format for import / export of workflow definition.
+ */
+public enum WorkflowDefinitionFormat {
+
+ XML,
+ JSON
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowException.java
----------------------------------------------------------------------
diff --git a/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowException.java b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowException.java
new file mode 100644
index 0000000..2468893
--- /dev/null
+++ b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowException.java
@@ -0,0 +1,51 @@
+/*
+ * 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.server.workflow.api;
+
+/**
+ * Wrapper for all workflow related exceptions. Original exceptions will depend on UserWorkflowAdapter implementation.
+ *
+ * @see UserWorkflowAdapter
+ */
+public class WorkflowException extends RuntimeException {
+
+ /**
+ * Generated serialVersionUID.
+ */
+ private static final long serialVersionUID = -6261173250078013869L;
+
+ /**
+ * Return a new instance wrapping the original workflow exception.
+ *
+ * @param cause original workflow exception
+ */
+ public WorkflowException(final Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Return a new instance wrapping the original workflow exception, additionally providing a local message.
+ *
+ * @param message local message
+ * @param cause original workflow exception
+ */
+ public WorkflowException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowInstanceLoader.java
----------------------------------------------------------------------
diff --git a/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowInstanceLoader.java b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowInstanceLoader.java
new file mode 100644
index 0000000..6271ec6
--- /dev/null
+++ b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/WorkflowInstanceLoader.java
@@ -0,0 +1,28 @@
+/*
+ * 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.server.workflow.api;
+
+public interface WorkflowInstanceLoader {
+
+ void load();
+
+ String getTablePrefix();
+
+ void init();
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/package-info.java
----------------------------------------------------------------------
diff --git a/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/package-info.java b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/package-info.java
new file mode 100644
index 0000000..bb79624
--- /dev/null
+++ b/syncope620/server/workflow-api/src/main/java/org/apache/syncope/server/workflow/api/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.server.workflow.api;
[12/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SearchableFields.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SearchableFields.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SearchableFields.java
new file mode 100644
index 0000000..5a006f5
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SearchableFields.java
@@ -0,0 +1,67 @@
+/*
+ * 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.common.lib.search;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.SubjectType;
+
+public class SearchableFields {
+
+ protected static final String[] ATTRIBUTES_NOTINCLUDED = {
+ "plainAttrs", "derAttrs", "virAttrs",
+ "serialVersionUID", "memberships", "entitlements", "resources", "password",
+ "propagationTOs", "propagationStatusMap"
+ };
+
+ public static final List<String> get(final SubjectType subjectType) {
+ return get(subjectType == SubjectType.USER
+ ? UserTO.class
+ : RoleTO.class);
+ }
+
+ public static final List<String> get(final Class<? extends AbstractAttributableTO> attributableRef) {
+ final List<String> fieldNames = new ArrayList<>();
+
+ // loop on class and all superclasses searching for field
+ Class<?> clazz = attributableRef;
+ while (clazz != null && clazz != Object.class) {
+ for (Field field : clazz.getDeclaredFields()) {
+ if (!ArrayUtils.contains(ATTRIBUTES_NOTINCLUDED, field.getName())) {
+ fieldNames.add(field.getName());
+ }
+ }
+ clazz = clazz.getSuperclass();
+ }
+
+ Collections.reverse(fieldNames);
+ return fieldNames;
+
+ }
+
+ private SearchableFields() {
+ // empty constructor for static utility class
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
new file mode 100644
index 0000000..b4c2f21
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SpecialAttr.java
@@ -0,0 +1,50 @@
+/*
+ * 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.common.lib.search;
+
+public enum SpecialAttr {
+
+ NULL("$null"),
+ RESOURCES("$resources"),
+ ROLES("$roles"),
+ ENTITLEMENTS("$entitlements");
+
+ private final String literal;
+
+ SpecialAttr(final String literal) {
+ this.literal = literal;
+ }
+
+ public static SpecialAttr fromString(final String value) {
+ SpecialAttr result = null;
+ for (SpecialAttr specialAttr : values()) {
+ if (specialAttr.literal.equals(value)) {
+ result = specialAttr;
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return literal;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SyncopeFiqlSearchConditionBuilder.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SyncopeFiqlSearchConditionBuilder.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SyncopeFiqlSearchConditionBuilder.java
new file mode 100644
index 0000000..6c710a2
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SyncopeFiqlSearchConditionBuilder.java
@@ -0,0 +1,110 @@
+/*
+ * 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.common.lib.search;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.cxf.jaxrs.ext.search.SearchUtils;
+import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
+import org.apache.cxf.jaxrs.ext.search.client.FiqlSearchConditionBuilder;
+import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser;
+
+public abstract class SyncopeFiqlSearchConditionBuilder extends FiqlSearchConditionBuilder {
+
+ public static final Map<String, String> CONTEXTUAL_PROPERTIES;
+
+ static {
+ CONTEXTUAL_PROPERTIES = new HashMap<String, String>();
+ CONTEXTUAL_PROPERTIES.put(SearchUtils.LAX_PROPERTY_MATCH, "true");
+ }
+
+ protected SyncopeFiqlSearchConditionBuilder() {
+ super();
+ }
+
+ protected SyncopeFiqlSearchConditionBuilder(final Map<String, String> properties) {
+ super(properties);
+ }
+
+ @Override
+ protected Builder newBuilderInstance() {
+ return new Builder(properties);
+ }
+
+ public SyncopeProperty is(final String property) {
+ return newBuilderInstance().is(property);
+ }
+
+ public CompleteCondition isNull(final String property) {
+ return newBuilderInstance().is(property).nullValue();
+ }
+
+ public CompleteCondition isNotNull(final String property) {
+ return newBuilderInstance().is(property).notNullValue();
+ }
+
+ public CompleteCondition hasResources(final String resource, final String... moreResources) {
+ return newBuilderInstance().is(SpecialAttr.RESOURCES.toString()).hasResources(resource, moreResources);
+ }
+
+ public CompleteCondition hasNotResources(final String resource, final String... moreResources) {
+ return newBuilderInstance().is(SpecialAttr.RESOURCES.toString()).hasNotResources(resource, moreResources);
+ }
+
+ protected static class Builder extends FiqlSearchConditionBuilder.Builder
+ implements SyncopeProperty, CompleteCondition {
+
+ protected Builder(final Map<String, String> properties) {
+ super(properties);
+ }
+
+ protected Builder(final Builder parent) {
+ super(parent);
+ }
+
+ @Override
+ public SyncopeProperty is(final String property) {
+ Builder b = new Builder(this);
+ b.result = property;
+ return b;
+ }
+
+ @Override
+ public CompleteCondition nullValue() {
+ return condition(FiqlParser.EQ, SpecialAttr.NULL);
+ }
+
+ @Override
+ public CompleteCondition notNullValue() {
+ return condition(FiqlParser.NEQ, SpecialAttr.NULL);
+ }
+
+ @Override
+ public CompleteCondition hasResources(final String resource, final String... moreResources) {
+ this.result = SpecialAttr.RESOURCES.toString();
+ return condition(FiqlParser.EQ, resource, (Object[]) moreResources);
+ }
+
+ @Override
+ public CompleteCondition hasNotResources(final String resource, final String... moreResources) {
+ this.result = SpecialAttr.RESOURCES.toString();
+ return condition(FiqlParser.NEQ, resource, (Object[]) moreResources);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SyncopeProperty.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SyncopeProperty.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SyncopeProperty.java
new file mode 100644
index 0000000..0f833f8
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/SyncopeProperty.java
@@ -0,0 +1,37 @@
+/*
+ * 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.common.lib.search;
+
+import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
+import org.apache.cxf.jaxrs.ext.search.client.Property;
+
+/**
+ * Extension of fluent interface, for {@link SyncopeFiqlSearchConditionBuilder}.
+ */
+public abstract interface SyncopeProperty extends Property {
+
+ CompleteCondition nullValue();
+
+ CompleteCondition notNullValue();
+
+ CompleteCondition hasResources(String resource, String... moreResources);
+
+ CompleteCondition hasNotResources(String resource, String... moreResources);
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserFiqlSearchConditionBuilder.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserFiqlSearchConditionBuilder.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserFiqlSearchConditionBuilder.java
new file mode 100644
index 0000000..ef16e3d
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserFiqlSearchConditionBuilder.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.search;
+
+import java.util.Map;
+import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
+import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser;
+
+/**
+ * Extends <tt>SyncopeFiqlSearchConditionBuilder</tt> by providing some additional facilities for searching
+ * users in Syncope.
+ */
+public class UserFiqlSearchConditionBuilder extends SyncopeFiqlSearchConditionBuilder {
+
+ public UserFiqlSearchConditionBuilder() {
+ super();
+ }
+
+ public UserFiqlSearchConditionBuilder(final Map<String, String> properties) {
+ super(properties);
+ }
+
+ @Override
+ protected Builder newBuilderInstance() {
+ return new Builder(properties);
+ }
+
+ @Override
+ public UserProperty is(final String property) {
+ return newBuilderInstance().is(property);
+ }
+
+ public CompleteCondition hasRoles(final Long role, final Long... moreRoles) {
+ return newBuilderInstance().is(SpecialAttr.ROLES.toString()).hasRoles(role, moreRoles);
+ }
+
+ public CompleteCondition hasNotRoles(final Long role, final Long... moreRoles) {
+ return newBuilderInstance().is(SpecialAttr.ROLES.toString()).hasNotRoles(role, moreRoles);
+ }
+
+ public CompleteCondition hasResources(final String resource, final String... moreResources) {
+ return newBuilderInstance().is(SpecialAttr.RESOURCES.toString()).hasResources(resource, moreResources);
+ }
+
+ public CompleteCondition hasNotResources(final String resource, final String... moreResources) {
+ return newBuilderInstance().is(SpecialAttr.RESOURCES.toString()).hasNotResources(resource, moreResources);
+ }
+
+ protected static class Builder extends SyncopeFiqlSearchConditionBuilder.Builder
+ implements UserProperty, CompleteCondition {
+
+ public Builder(final Map<String, String> properties) {
+ super(properties);
+ }
+
+ public Builder(final Builder parent) {
+ super(parent);
+ }
+
+ @Override
+ public UserProperty is(final String property) {
+ Builder b = new Builder(this);
+ b.result = property;
+ return b;
+ }
+
+ @Override
+ public CompleteCondition hasRoles(final Long role, final Long... moreRoles) {
+ this.result = SpecialAttr.ROLES.toString();
+ return condition(FiqlParser.EQ, role, (Object[]) moreRoles);
+ }
+
+ @Override
+ public CompleteCondition hasNotRoles(final Long role, final Long... moreRoles) {
+ this.result = SpecialAttr.ROLES.toString();
+ return condition(FiqlParser.NEQ, role, (Object[]) moreRoles);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserProperty.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserProperty.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserProperty.java
new file mode 100644
index 0000000..886f27f
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/UserProperty.java
@@ -0,0 +1,29 @@
+/*
+ * 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.common.lib.search;
+
+import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
+
+public interface UserProperty extends SyncopeProperty {
+
+ CompleteCondition hasRoles(Long role, Long... moreRoles);
+
+ CompleteCondition hasNotRoles(Long role, Long... moreRoles);
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractAttributableTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractAttributableTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractAttributableTO.java
index 5cb48bb..0794b09 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractAttributableTO.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractAttributableTO.java
@@ -34,18 +34,18 @@ public abstract class AbstractAttributableTO extends ConnObjectTO {
private static final long serialVersionUID = 4083884098736820255L;
- private long id;
+ private long key;
private final List<AttrTO> derAttrs = new ArrayList<>();
private final List<AttrTO> virAttrs = new ArrayList<>();
- public long getId() {
- return id;
+ public long getKey() {
+ return key;
}
- public void setId(final long id) {
- this.id = id;
+ public void setKey(final long id) {
+ this.key = id;
}
@JsonIgnore
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractExecTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractExecTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractExecTO.java
new file mode 100644
index 0000000..71b735f
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractExecTO.java
@@ -0,0 +1,87 @@
+/*
+ * 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.common.lib.to;
+
+import java.util.Date;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlType
+public class AbstractExecTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -4621191979198357081L;
+
+ protected long key;
+
+ protected String status;
+
+ protected String message;
+
+ protected Date startDate;
+
+ protected Date endDate;
+
+ public long getKey() {
+ return key;
+ }
+
+ public void setKey(long key) {
+ this.key = key;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(final String message) {
+ this.message = message;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(final String status) {
+ this.status = status;
+ }
+
+ public Date getStartDate() {
+ return startDate == null
+ ? null
+ : new Date(startDate.getTime());
+ }
+
+ public void setStartDate(final Date startDate) {
+ if (startDate != null) {
+ this.startDate = new Date(startDate.getTime());
+ }
+ }
+
+ public Date getEndDate() {
+ return endDate == null
+ ? null
+ : new Date(endDate.getTime());
+ }
+
+ public void setEndDate(final Date endDate) {
+ if (endDate != null) {
+ this.endDate = new Date(endDate.getTime());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractPolicyTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractPolicyTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractPolicyTO.java
new file mode 100644
index 0000000..4423e41
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractPolicyTO.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.PolicyType;
+
+@XmlRootElement(name = "abstractPolicy")
+@XmlType
+@XmlSeeAlso({ AccountPolicyTO.class, PasswordPolicyTO.class, SyncPolicyTO.class })
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
+public abstract class AbstractPolicyTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -2903888572649721035L;
+
+ private long id;
+
+ private String description;
+
+ private PolicyType type;
+
+ private final List<String> usedByResources = new ArrayList<>();
+
+ private final List<Long> usedByRoles = new ArrayList<>();
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ public PolicyType getType() {
+ return type;
+ }
+
+ public void setType(final PolicyType type) {
+ this.type = type;
+ }
+
+ @XmlElementWrapper(name = "usedByResources")
+ @XmlElement(name = "resource")
+ @JsonProperty("usedByResources")
+ public List<String> getUsedByResources() {
+ return usedByResources;
+ }
+
+ @XmlElementWrapper(name = "usedByRoles")
+ @XmlElement(name = "role")
+ @JsonProperty("usedByRoles")
+ public List<Long> getUsedByRoles() {
+ return usedByRoles;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractProvisioningTaskTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractProvisioningTaskTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractProvisioningTaskTO.java
new file mode 100644
index 0000000..fe92877
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractProvisioningTaskTO.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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.types.MatchingRule;
+import org.apache.syncope.common.lib.types.UnmatchingRule;
+
+@XmlRootElement(name = "abstractProvisioningTask")
+@XmlType
+@XmlSeeAlso({ PushTaskTO.class, SyncTaskTO.class })
+public class AbstractProvisioningTaskTO extends SchedTaskTO {
+
+ private static final long serialVersionUID = -2143537546915809016L;
+
+ private String resource;
+
+ private boolean performCreate;
+
+ private boolean performUpdate;
+
+ private boolean performDelete;
+
+ private boolean syncStatus;
+
+ private UnmatchingRule unmatchingRule;
+
+ private MatchingRule matchingRule;
+
+ private List<String> actionsClassNames = new ArrayList<>();
+
+ public String getResource() {
+ return resource;
+ }
+
+ public void setResource(String resource) {
+ this.resource = resource;
+ }
+
+ public boolean isPerformCreate() {
+ return performCreate;
+ }
+
+ public void setPerformCreate(boolean performCreate) {
+ this.performCreate = performCreate;
+ }
+
+ public boolean isPerformUpdate() {
+ return performUpdate;
+ }
+
+ public void setPerformUpdate(boolean performUpdate) {
+ this.performUpdate = performUpdate;
+ }
+
+ public boolean isPerformDelete() {
+ return performDelete;
+ }
+
+ public void setPerformDelete(boolean performDelete) {
+ this.performDelete = performDelete;
+ }
+
+ public boolean isSyncStatus() {
+ return syncStatus;
+ }
+
+ public void setSyncStatus(boolean syncStatus) {
+ this.syncStatus = syncStatus;
+ }
+
+ @XmlElementWrapper(name = "actionsClassNames")
+ @XmlElement(name = "actionsClassName")
+ @JsonProperty("actionsClassNames")
+ public List<String> getActionsClassNames() {
+ return actionsClassNames;
+ }
+
+ public UnmatchingRule getUnmatchingRule() {
+ return unmatchingRule;
+ }
+
+ public void setUnmatchingRule(final UnmatchingRule unmatchigRule) {
+ this.unmatchingRule = unmatchigRule;
+ }
+
+ public MatchingRule getMatchingRule() {
+ return matchingRule;
+ }
+
+ public void setMatchingRule(final MatchingRule matchigRule) {
+ this.matchingRule = matchigRule;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractSchemaTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractSchemaTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractSchemaTO.java
new file mode 100644
index 0000000..b3a37a8
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractSchemaTO.java
@@ -0,0 +1,44 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlRootElement(name = "abstractSchema")
+@XmlType
+@XmlSeeAlso({ PlainSchemaTO.class, DerSchemaTO.class, VirSchemaTO.class })
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
+public abstract class AbstractSchemaTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 4088388951694301759L;
+
+ private String key;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(final String key) {
+ this.key = key;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractTaskTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractTaskTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractTaskTO.java
new file mode 100644
index 0000000..6ed1750
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AbstractTaskTO.java
@@ -0,0 +1,98 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlRootElement(name = "abstractTask")
+@XmlType
+@XmlSeeAlso({ PropagationTaskTO.class, SchedTaskTO.class, NotificationTaskTO.class })
+@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
+public abstract class AbstractTaskTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 386450127003321197L;
+
+ private long id;
+
+ private String latestExecStatus;
+
+ private List<TaskExecTO> executions = new ArrayList<>();
+
+ private Date startDate;
+
+ private Date endDate;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(final long id) {
+ this.id = id;
+ }
+
+ public String getLatestExecStatus() {
+ return latestExecStatus;
+ }
+
+ public void setLatestExecStatus(final String latestExecStatus) {
+ this.latestExecStatus = latestExecStatus;
+ }
+
+ @XmlElementWrapper(name = "executions")
+ @XmlElement(name = "execution")
+ @JsonProperty("executions")
+ public List<TaskExecTO> getExecutions() {
+ return executions;
+ }
+
+ public Date getStartDate() {
+ return startDate == null
+ ? null
+ : new Date(startDate.getTime());
+ }
+
+ public void setStartDate(final Date startDate) {
+ if (startDate != null) {
+ this.startDate = new Date(startDate.getTime());
+ }
+ }
+
+ public Date getEndDate() {
+ return endDate == null
+ ? null
+ : new Date(endDate.getTime());
+ }
+
+ public void setEndDate(final Date endDate) {
+ if (endDate != null) {
+ this.endDate = new Date(endDate.getTime());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AccountPolicyTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AccountPolicyTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AccountPolicyTO.java
new file mode 100644
index 0000000..a58b24f
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/AccountPolicyTO.java
@@ -0,0 +1,68 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.types.AccountPolicySpec;
+import org.apache.syncope.common.lib.types.PolicyType;
+
+@XmlRootElement(name = "accountPolicy")
+@XmlType
+public class AccountPolicyTO extends AbstractPolicyTO {
+
+ private static final long serialVersionUID = -1557150042828800134L;
+
+ private AccountPolicySpec specification;
+
+ private final List<String> resources = new ArrayList<String>();
+
+ public AccountPolicyTO() {
+ this(false);
+ }
+
+ public AccountPolicyTO(final boolean global) {
+ super();
+
+ PolicyType type = global
+ ? PolicyType.GLOBAL_ACCOUNT
+ : PolicyType.ACCOUNT;
+ setType(type);
+ }
+
+ public void setSpecification(final AccountPolicySpec specification) {
+ this.specification = specification;
+ }
+
+ public AccountPolicySpec getSpecification() {
+ return specification;
+ }
+
+ @XmlElementWrapper(name = "resources")
+ @XmlElement(name = "resource")
+ @JsonProperty("resources")
+ public List<String> getResources() {
+ return resources;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/BulkAction.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/BulkAction.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/BulkAction.java
new file mode 100644
index 0000000..a514dcb
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/BulkAction.java
@@ -0,0 +1,70 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlRootElement(name = "bulkAction")
+@XmlType
+public class BulkAction extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 1395353278878758961L;
+
+ @XmlEnum
+ @XmlType(name = "bulkActionType")
+ public enum Type {
+
+ DELETE,
+ REACTIVATE,
+ SUSPEND,
+ DRYRUN,
+ EXECUTE
+
+ }
+
+ private Type operation;
+
+ /**
+ * Serialized identifiers.
+ */
+ private final List<String> targets = new ArrayList<>();
+
+ public Type getOperation() {
+ return operation;
+ }
+
+ public void setOperation(final Type operation) {
+ this.operation = operation;
+ }
+
+ @XmlElementWrapper(name = "targets")
+ @XmlElement(name = "target")
+ @JsonProperty("targets")
+ public List<String> getTargets() {
+ return targets;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/BulkActionResult.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/BulkActionResult.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/BulkActionResult.java
new file mode 100644
index 0000000..dfe52de
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/BulkActionResult.java
@@ -0,0 +1,134 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlRootElement(name = "bulkActionResult")
+@XmlType
+public class BulkActionResult extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 2868894178821778133L;
+
+ @XmlEnum
+ @XmlType(name = "bulkActionStatus")
+ public enum Status {
+
+ // general bulk action result statuses
+ SUCCESS,
+ FAILURE,
+ // specific propagation task execution statuses
+ CREATED,
+ SUBMITTED,
+ UNSUBMITTED;
+
+ }
+
+ private final List<Result> results = new ArrayList<Result>();
+
+ @XmlElementWrapper(name = "result")
+ @XmlElement(name = "item")
+ @JsonProperty("result")
+ public List<Result> getResult() {
+ return results;
+ }
+
+ @JsonIgnore
+ public void add(final Object id, final Status status) {
+ if (id != null) {
+ results.add(new Result(id.toString(), status));
+ }
+ }
+
+ @JsonIgnore
+ public void add(final Object id, final String status) {
+ if (id != null) {
+ results.add(new Result(id.toString(), Status.valueOf(status.toUpperCase())));
+ }
+ }
+
+ @JsonIgnore
+ public Map<String, Status> getResultMap() {
+ final Map<String, Status> res = new HashMap<String, Status>();
+
+ for (Result result : results) {
+ res.put(result.getKey(), result.getValue());
+ }
+
+ return res;
+ }
+
+ @JsonIgnore
+ public List<String> getResultByStatus(final Status status) {
+ final List<String> res = new ArrayList<String>();
+
+ for (Result result : results) {
+ if (result.getValue() == status) {
+ res.add(result.getKey());
+ }
+ }
+
+ return res;
+ }
+
+ public static class Result extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -1149681964161193232L;
+
+ private String key;
+
+ private Status value;
+
+ public Result() {
+ super();
+ }
+
+ public Result(final String key, final Status value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public Status getValue() {
+ return value;
+ }
+
+ public void setKey(final String key) {
+ this.key = key;
+ }
+
+ public void setValue(final Status value) {
+ this.value = value;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConfTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConfTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConfTO.java
new file mode 100644
index 0000000..4856a48
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConfTO.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "conf")
+@XmlType
+public class ConfTO extends AbstractAttributableTO {
+
+ private static final long serialVersionUID = -3825039700228595590L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnBundleTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnBundleTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnBundleTO.java
new file mode 100644
index 0000000..87583a4
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnBundleTO.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.ConnConfPropSchema;
+
+@XmlRootElement(name = "connectorBundle")
+@XmlType
+public class ConnBundleTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 7215115961910138005L;
+
+ private String displayName;
+
+ private String location;
+
+ private String bundleName;
+
+ private String connectorName;
+
+ private String version;
+
+ private List<ConnConfPropSchema> properties = new ArrayList<>();
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setDisplayName(final String displayName) {
+ this.displayName = displayName;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ public void setLocation(final String location) {
+ this.location = location;
+ }
+
+ public String getBundleName() {
+ return bundleName;
+ }
+
+ public void setBundleName(final String bundleName) {
+ this.bundleName = bundleName;
+ }
+
+ public String getConnectorName() {
+ return connectorName;
+ }
+
+ public void setConnectorName(final String connectorName) {
+ this.connectorName = connectorName;
+ }
+
+ @XmlElementWrapper(name = "properties")
+ @XmlElement(name = "connConfPropSchema")
+ @JsonProperty("properties")
+ public List<ConnConfPropSchema> getProperties() {
+ return properties;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(final String version) {
+ this.version = version;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
new file mode 100644
index 0000000..5c25783
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnInstanceTO.java
@@ -0,0 +1,177 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.common.lib.types.ConnectorCapability;
+
+@XmlRootElement(name = "connInstance")
+@XmlType
+public class ConnInstanceTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 2707778645445168671L;
+
+ private long key;
+
+ private String location;
+
+ private String connectorName;
+
+ private String bundleName;
+
+ private String version;
+
+ private final Set<ConnConfProperty> configuration;
+
+ private final Set<ConnectorCapability> capabilities;
+
+ private String displayName;
+
+ private Integer connRequestTimeout;
+
+ private ConnPoolConfTO poolConf;
+
+ public ConnInstanceTO() {
+ super();
+
+ configuration = new HashSet<>();
+ capabilities = EnumSet.noneOf(ConnectorCapability.class);
+ }
+
+ public long getKey() {
+ return key;
+ }
+
+ public void setKey(final long key) {
+ this.key = key;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ public void setLocation(final String location) {
+ this.location = location;
+ }
+
+ public String getConnectorName() {
+ return connectorName;
+ }
+
+ public void setConnectorName(final String connectorname) {
+ this.connectorName = connectorname;
+ }
+
+ public String getBundleName() {
+ return bundleName;
+ }
+
+ public void setBundleName(final String bundlename) {
+ this.bundleName = bundlename;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(final String version) {
+ this.version = version;
+ }
+
+ @XmlElementWrapper(name = "configuration")
+ @XmlElement(name = "property")
+ @JsonProperty("configuration")
+ public Set<ConnConfProperty> getConfiguration() {
+ return this.configuration;
+ }
+
+ @JsonIgnore
+ public Map<String, ConnConfProperty> getConfigurationMap() {
+ Map<String, ConnConfProperty> result;
+
+ if (getConfiguration() == null) {
+ result = Collections.<String, ConnConfProperty>emptyMap();
+ } else {
+ result = new HashMap<>();
+ for (ConnConfProperty prop : getConfiguration()) {
+ result.put(prop.getSchema().getName(), prop);
+ }
+ result = Collections.unmodifiableMap(result);
+ }
+
+ return result;
+ }
+
+ @XmlElementWrapper(name = "capabilities")
+ @XmlElement(name = "capability")
+ @JsonProperty("capabilities")
+ public Set<ConnectorCapability> getCapabilities() {
+ return capabilities;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public void setDisplayName(final String displayName) {
+ this.displayName = displayName;
+ }
+
+ /**
+ * Get connector request timeout.
+ * It is not applied in case of sync, full reconciliation and search.
+ *
+ * @return timeout.
+ */
+ public Integer getConnRequestTimeout() {
+ return connRequestTimeout;
+ }
+
+ /**
+ * Set connector request timeout.
+ * It is not applied in case of sync, full reconciliation and search.
+ *
+ * @param connRequestTimeout timeout
+ */
+ public void setConnRequestTimeout(final Integer connRequestTimeout) {
+ this.connRequestTimeout = connRequestTimeout;
+ }
+
+ public ConnPoolConfTO getPoolConf() {
+ return poolConf;
+ }
+
+ public void setPoolConf(final ConnPoolConfTO poolConf) {
+ this.poolConf = poolConf;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/DerSchemaTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/DerSchemaTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/DerSchemaTO.java
new file mode 100644
index 0000000..dc84864
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/DerSchemaTO.java
@@ -0,0 +1,39 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "derivedSchema")
+@XmlType
+public class DerSchemaTO extends AbstractSchemaTO {
+
+ private static final long serialVersionUID = -6747399803792103108L;
+
+ private String expression;
+
+ public String getExpression() {
+ return expression;
+ }
+
+ public void setExpression(final String expression) {
+ this.expression = expression;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ErrorTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ErrorTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ErrorTO.java
new file mode 100644
index 0000000..e0f14ad
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ErrorTO.java
@@ -0,0 +1,66 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+
+@XmlRootElement(name = "error")
+@XmlType
+public class ErrorTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 2435764161719225927L;
+
+ private int status;
+
+ private ClientExceptionType type;
+
+ private final List<Object> elements = new ArrayList<>();
+
+ public int getStatus() {
+ return status;
+ }
+
+ public void setStatus(final int status) {
+ this.status = status;
+ }
+
+ public ClientExceptionType getType() {
+ return type;
+ }
+
+ public void setType(final ClientExceptionType type) {
+ this.type = type;
+ }
+
+ @XmlElementWrapper(name = "elements")
+ @XmlElement(name = "element")
+ @JsonProperty("elements")
+ public List<Object> getElements() {
+ return elements;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/EventCategoryTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/EventCategoryTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/EventCategoryTO.java
new file mode 100644
index 0000000..8e11686
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/EventCategoryTO.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.AuditElements;
+
+@XmlRootElement(name = "eventCategory")
+@XmlType
+public class EventCategoryTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -4340060002701633401L;
+
+ private AuditElements.EventCategoryType type;
+
+ private String category;
+
+ private String subcategory;
+
+ private final List<String> events = new ArrayList<String>();
+
+ /**
+ * Constructor for Type.REST event category.
+ */
+ public EventCategoryTO() {
+ this.type = AuditElements.EventCategoryType.REST;
+ }
+
+ /**
+ * Constructor for the given Type event category.
+ */
+ public EventCategoryTO(final AuditElements.EventCategoryType type) {
+ this.type = type;
+ }
+
+ public AuditElements.EventCategoryType getType() {
+ return type;
+ }
+
+ public void setType(final AuditElements.EventCategoryType type) {
+ this.type = type == null ? AuditElements.EventCategoryType.CUSTOM : type;
+ }
+
+ public String getCategory() {
+ return category;
+ }
+
+ public void setCategory(final String category) {
+ this.category = category;
+ }
+
+ public String getSubcategory() {
+ return subcategory;
+ }
+
+ public void setSubcategory(final String subcategory) {
+ this.subcategory = subcategory;
+ }
+
+ @XmlElementWrapper(name = "events")
+ @XmlElement(name = "event")
+ @JsonProperty("events")
+ public List<String> getEvents() {
+ return events;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/LoggerTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/LoggerTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/LoggerTO.java
new file mode 100644
index 0000000..263ab97
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/LoggerTO.java
@@ -0,0 +1,51 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.LoggerLevel;
+
+@XmlRootElement(name = "logger")
+@XmlType
+public class LoggerTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -7794833835668648505L;
+
+ private String name;
+
+ private LoggerLevel level;
+
+ public LoggerLevel getLevel() {
+ return level;
+ }
+
+ public void setLevel(final LoggerLevel level) {
+ this.level = level;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
new file mode 100644
index 0000000..4df561c
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingItemTO.java
@@ -0,0 +1,134 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+
+@XmlRootElement(name = "mappingItem")
+@XmlType
+public class MappingItemTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 2983498836767176862L;
+
+ private Long key;
+
+ /**
+ * Attribute schema to be mapped. Consider that we can associate tha same attribute schema more than once, with
+ * different aliases, to different resource attributes.
+ */
+ private String intAttrName;
+
+ /**
+ * Schema type to be mapped.
+ */
+ private IntMappingType intMappingType;
+
+ /**
+ * External resource's field to be mapped.
+ */
+ private String extAttrName;
+
+ /**
+ * Specify if the mapped target resource's field is the key.
+ */
+ private boolean accountid;
+
+ /**
+ * Specify if the mapped target resource's field is the password.
+ */
+ private boolean password;
+
+ /**
+ * Specify if the mapped target resource's field is nullable.
+ */
+ private String mandatoryCondition = "false";
+
+ /**
+ * Mapping purposes: SYNCHRONIZATION, PROPAGATION, BOTH, NONE.
+ */
+ private MappingPurpose purpose;
+
+ public boolean isAccountid() {
+ return accountid;
+ }
+
+ public void setAccountid(final boolean accountid) {
+ this.accountid = accountid;
+ }
+
+ public String getExtAttrName() {
+ return extAttrName;
+ }
+
+ public void setExtAttrName(final String extAttrName) {
+ this.extAttrName = extAttrName;
+ }
+
+ public Long getKey() {
+ return key;
+ }
+
+ public void setKey(final Long key) {
+ this.key = key;
+ }
+
+ public String getMandatoryCondition() {
+ return mandatoryCondition;
+ }
+
+ public void setMandatoryCondition(final String mandatoryCondition) {
+ this.mandatoryCondition = mandatoryCondition;
+ }
+
+ public boolean isPassword() {
+ return password;
+ }
+
+ public void setPassword(final boolean password) {
+ this.password = password;
+ }
+
+ public String getIntAttrName() {
+ return intAttrName;
+ }
+
+ public void setIntAttrName(final String intAttrName) {
+ this.intAttrName = intAttrName;
+ }
+
+ public IntMappingType getIntMappingType() {
+ return intMappingType;
+ }
+
+ public void setIntMappingType(final IntMappingType intMappingType) {
+ this.intMappingType = intMappingType;
+ }
+
+ public MappingPurpose getPurpose() {
+ return purpose;
+ }
+
+ public void setPurpose(final MappingPurpose purpose) {
+ this.purpose = purpose;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
new file mode 100644
index 0000000..3d29914
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/MappingTO.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.IntMappingType;
+
+@XmlRootElement(name = "mapping")
+@XmlType
+public class MappingTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 8447688036282611118L;
+
+ private String accountLink;
+
+ private final List<MappingItemTO> items = new ArrayList<>();
+
+ public String getAccountLink() {
+ return accountLink;
+ }
+
+ public void setAccountLink(final String accountLink) {
+ this.accountLink = accountLink;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends MappingItemTO> T getAccountIdItem() {
+ T accountIdItem = null;
+ for (MappingItemTO item : getItems()) {
+ if (item.isAccountid()) {
+ accountIdItem = (T) item;
+ }
+ }
+ return accountIdItem;
+ }
+
+ protected <T extends MappingItemTO> boolean addAccountIdItem(final T accountIdItem) {
+ if (IntMappingType.UserVirtualSchema == accountIdItem.getIntMappingType()
+ || IntMappingType.RoleVirtualSchema == accountIdItem.getIntMappingType()
+ || IntMappingType.MembershipVirtualSchema == accountIdItem.getIntMappingType()
+ || IntMappingType.Password == accountIdItem.getIntMappingType()) {
+
+ throw new IllegalArgumentException("Virtual attributes cannot be set as accountId");
+ }
+ if (IntMappingType.Password == accountIdItem.getIntMappingType()) {
+ throw new IllegalArgumentException("Password attributes cannot be set as accountId");
+ }
+
+ accountIdItem.setExtAttrName(accountIdItem.getExtAttrName());
+ accountIdItem.setAccountid(true);
+
+ return this.addItem(accountIdItem);
+ }
+
+ public boolean setAccountIdItem(final MappingItemTO accountIdItem) {
+ if (accountIdItem == null) {
+ return this.removeItem(getAccountIdItem());
+ } else {
+ return addAccountIdItem(accountIdItem);
+ }
+ }
+
+ public MappingItemTO getPasswordItem() {
+ MappingItemTO passwordItem = null;
+ for (MappingItemTO item : getItems()) {
+ if (item.isPassword()) {
+ passwordItem = item;
+ }
+ }
+ return passwordItem;
+ }
+
+ public boolean setPasswordItem(final MappingItemTO passwordItem) {
+ if (passwordItem == null) {
+ return this.removeItem(getPasswordItem());
+ } else {
+ passwordItem.setExtAttrName(null);
+ passwordItem.setPassword(true);
+ return addItem(passwordItem);
+ }
+ }
+
+ @XmlElementWrapper(name = "items")
+ @XmlElement(name = "item")
+ @JsonProperty("items")
+ public List<MappingItemTO> getItems() {
+ return items;
+ }
+
+ public boolean addItem(final MappingItemTO item) {
+ return item == null ? false : this.items.contains(item) || this.items.add(item);
+ }
+
+ public boolean removeItem(final MappingItemTO item) {
+ return this.items.remove(item);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTO.java
new file mode 100644
index 0000000..b921e53
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTO.java
@@ -0,0 +1,175 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.TraceLevel;
+
+@XmlRootElement(name = "notification")
+@XmlType
+public class NotificationTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -6145117115632592612L;
+
+ private Long key;
+
+ private List<String> events = new ArrayList<>();
+
+ private String userAbout;
+
+ private String roleAbout;
+
+ private String recipients;
+
+ private List<String> staticRecipients = new ArrayList<>();
+
+ private IntMappingType recipientAttrType;
+
+ private String recipientAttrName;
+
+ private boolean selfAsRecipient;
+
+ private String sender;
+
+ private String subject;
+
+ private String template;
+
+ private TraceLevel traceLevel;
+
+ private boolean active;
+
+ public String getUserAbout() {
+ return userAbout;
+ }
+
+ public void setUserAbout(final String userAbout) {
+ this.userAbout = userAbout;
+ }
+
+ public String getRoleAbout() {
+ return roleAbout;
+ }
+
+ public void setRoleAbout(final String roleAbout) {
+ this.roleAbout = roleAbout;
+ }
+
+ @XmlElementWrapper(name = "events")
+ @XmlElement(name = "event")
+ @JsonProperty("events")
+ public List<String> getEvents() {
+ return events;
+ }
+
+ @XmlElementWrapper(name = "staticRecipients")
+ @XmlElement(name = "staticRecipient")
+ @JsonProperty("staticRecipients")
+ public List<String> getStaticRecipients() {
+ return staticRecipients;
+ }
+
+ public Long getKey() {
+ return key;
+ }
+
+ public void setKey(Long key) {
+ this.key = key;
+ }
+
+ public String getRecipients() {
+ return recipients;
+ }
+
+ public void setRecipients(final String recipients) {
+ this.recipients = recipients;
+ }
+
+ public String getRecipientAttrName() {
+ return recipientAttrName;
+ }
+
+ public void setRecipientAttrName(final String recipientAttrName) {
+ this.recipientAttrName = recipientAttrName;
+ }
+
+ public IntMappingType getRecipientAttrType() {
+ return recipientAttrType;
+ }
+
+ public void setRecipientAttrType(final IntMappingType recipientAttrType) {
+ this.recipientAttrType = recipientAttrType;
+ }
+
+ public boolean isSelfAsRecipient() {
+ return selfAsRecipient;
+ }
+
+ public void setSelfAsRecipient(final boolean selfAsRecipient) {
+ this.selfAsRecipient = selfAsRecipient;
+ }
+
+ public String getSender() {
+ return sender;
+ }
+
+ public void setSender(final String sender) {
+ this.sender = sender;
+ }
+
+ public String getSubject() {
+ return subject;
+ }
+
+ public void setSubject(final String subject) {
+ this.subject = subject;
+ }
+
+ public String getTemplate() {
+ return template;
+ }
+
+ public void setTemplate(final String template) {
+ this.template = template;
+ }
+
+ public TraceLevel getTraceLevel() {
+ return traceLevel;
+ }
+
+ public void setTraceLevel(final TraceLevel traceLevel) {
+ this.traceLevel = traceLevel;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void setActive(final boolean active) {
+ this.active = active;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTaskTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTaskTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTaskTO.java
new file mode 100644
index 0000000..48661f9
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/NotificationTaskTO.java
@@ -0,0 +1,105 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.types.TraceLevel;
+
+@XmlRootElement(name = "notificationTask")
+@XmlType
+public class NotificationTaskTO extends AbstractTaskTO {
+
+ private static final long serialVersionUID = 371671242591093846L;
+
+ private final Set<String> recipients = new HashSet<>();
+
+ private String sender;
+
+ private String subject;
+
+ private String textBody;
+
+ private String htmlBody;
+
+ private boolean executed;
+
+ private TraceLevel traceLevel;
+
+ @XmlElementWrapper(name = "recipients")
+ @XmlElement(name = "recipient")
+ @JsonProperty("recipients")
+ public Set<String> getRecipients() {
+ return recipients;
+ }
+
+ public String getSender() {
+ return sender;
+ }
+
+ public void setSender(final String sender) {
+ this.sender = sender;
+ }
+
+ public String getSubject() {
+ return subject;
+ }
+
+ public void setSubject(final String subject) {
+ this.subject = subject;
+ }
+
+ public String getTextBody() {
+ return textBody;
+ }
+
+ public void setTextBody(final String textBody) {
+ this.textBody = textBody;
+ }
+
+ public String getHtmlBody() {
+ return htmlBody;
+ }
+
+ public void setHtmlBody(final String htmlBody) {
+ this.htmlBody = htmlBody;
+ }
+
+ public boolean isExecuted() {
+ return executed;
+ }
+
+ public void setExecuted(boolean executed) {
+ this.executed = executed;
+ }
+
+ public TraceLevel getTraceLevel() {
+ return traceLevel;
+ }
+
+ public void setTraceLevel(final TraceLevel traceLevel) {
+ this.traceLevel = traceLevel;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PagedResult.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PagedResult.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PagedResult.java
new file mode 100644
index 0000000..f383ece
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PagedResult.java
@@ -0,0 +1,98 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlRootElement(name = "pagedResult")
+@XmlType
+public class PagedResult<T extends AbstractBaseBean> extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 3472875885259250934L;
+
+ private URI prev;
+
+ private URI next;
+
+ private final List<T> result = new ArrayList<T>();
+
+ private int page;
+
+ private int size;
+
+ private int totalCount;
+
+ public URI getPrev() {
+ return prev;
+ }
+
+ public void setPrev(final URI prev) {
+ this.prev = prev;
+ }
+
+ public URI getNext() {
+ return next;
+ }
+
+ public void setNext(final URI next) {
+ this.next = next;
+ }
+
+ @XmlElementWrapper(name = "result")
+ @XmlElement(name = "item")
+ @JsonProperty("result")
+ @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
+ public List<T> getResult() {
+ return result;
+ }
+
+ public int getPage() {
+ return page;
+ }
+
+ public void setPage(final int page) {
+ this.page = page;
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public void setSize(final int size) {
+ this.size = size;
+ }
+
+ public int getTotalCount() {
+ return totalCount;
+ }
+
+ public void setTotalCount(final int totalCount) {
+ this.totalCount = totalCount;
+ }
+
+}
[11/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PasswordPolicyTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PasswordPolicyTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PasswordPolicyTO.java
new file mode 100644
index 0000000..05c4e5a
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PasswordPolicyTO.java
@@ -0,0 +1,54 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.types.PasswordPolicySpec;
+import org.apache.syncope.common.lib.types.PolicyType;
+
+@XmlRootElement(name = "passwordPolicy")
+@XmlType
+public class PasswordPolicyTO extends AbstractPolicyTO {
+
+ private static final long serialVersionUID = -5606086441294799690L;
+
+ private PasswordPolicySpec specification;
+
+ public PasswordPolicyTO() {
+ this(false);
+ }
+
+ public PasswordPolicyTO(boolean global) {
+ super();
+
+ PolicyType type = global
+ ? PolicyType.GLOBAL_PASSWORD
+ : PolicyType.PASSWORD;
+ setType(type);
+ }
+
+ public void setSpecification(final PasswordPolicySpec specification) {
+ this.specification = specification;
+ }
+
+ public PasswordPolicySpec getSpecification() {
+ return specification;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PlainSchemaTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PlainSchemaTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PlainSchemaTO.java
new file mode 100644
index 0000000..4568e36
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PlainSchemaTO.java
@@ -0,0 +1,156 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.common.lib.types.CipherAlgorithm;
+
+@XmlRootElement(name = "schema")
+@XmlType
+public class PlainSchemaTO extends AbstractSchemaTO {
+
+ private static final long serialVersionUID = -8133983392476990308L;
+
+ private AttrSchemaType type = AttrSchemaType.String;
+
+ private String mandatoryCondition;
+
+ private boolean multivalue;
+
+ private boolean uniqueConstraint;
+
+ private boolean readonly;
+
+ private String conversionPattern;
+
+ private String validatorClass;
+
+ private String enumerationValues;
+
+ private String enumerationKeys;
+
+ private String secretKey;
+
+ private CipherAlgorithm cipherAlgorithm;
+
+ private String mimeType;
+
+ public String getConversionPattern() {
+ return conversionPattern;
+ }
+
+ public void setConversionPattern(final String conversionPattern) {
+ this.conversionPattern = conversionPattern;
+ }
+
+ public String getMandatoryCondition() {
+ return StringUtils.isNotBlank(mandatoryCondition)
+ ? mandatoryCondition
+ : "false";
+ }
+
+ public void setMandatoryCondition(final String mandatoryCondition) {
+ this.mandatoryCondition = mandatoryCondition;
+ }
+
+ public boolean isMultivalue() {
+ return multivalue;
+ }
+
+ public void setMultivalue(final boolean multivalue) {
+ this.multivalue = multivalue;
+ }
+
+ public boolean isUniqueConstraint() {
+ return uniqueConstraint;
+ }
+
+ public void setUniqueConstraint(final boolean uniqueConstraint) {
+ this.uniqueConstraint = uniqueConstraint;
+ }
+
+ public boolean isReadonly() {
+ return readonly;
+ }
+
+ public void setReadonly(final boolean readonly) {
+ this.readonly = readonly;
+ }
+
+ public AttrSchemaType getType() {
+ return type;
+ }
+
+ public void setType(final AttrSchemaType type) {
+ this.type = type;
+ }
+
+ public String getValidatorClass() {
+ return validatorClass;
+ }
+
+ public void setValidatorClass(final String validatorClass) {
+ this.validatorClass = validatorClass;
+ }
+
+ public String getEnumerationValues() {
+ return enumerationValues;
+ }
+
+ public void setEnumerationValues(final String enumerationValues) {
+ this.enumerationValues = enumerationValues;
+ }
+
+ public String getEnumerationKeys() {
+ return enumerationKeys;
+ }
+
+ public void setEnumerationKeys(final String enumerationKeys) {
+ this.enumerationKeys = enumerationKeys;
+ }
+
+ public String getSecretKey() {
+ return secretKey;
+ }
+
+ public void setSecretKey(final String secretKey) {
+ this.secretKey = secretKey;
+ }
+
+ public CipherAlgorithm getCipherAlgorithm() {
+ return cipherAlgorithm;
+ }
+
+ public void setCipherAlgorithm(final CipherAlgorithm cipherAlgorithm) {
+ this.cipherAlgorithm = cipherAlgorithm;
+ }
+
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ public void setMimeType(final String mimeType) {
+ this.mimeType = mimeType;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PropagationTaskTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PropagationTaskTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PropagationTaskTO.java
new file mode 100644
index 0000000..7c6ec08
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PropagationTaskTO.java
@@ -0,0 +1,123 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.types.PropagationMode;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.common.lib.types.SubjectType;
+
+@XmlRootElement(name = "propagationTask")
+@XmlType
+public class PropagationTaskTO extends AbstractTaskTO {
+
+ private static final long serialVersionUID = 386450127003321197L;
+
+ private PropagationMode propagationMode;
+
+ private ResourceOperation propagationOperation;
+
+ private String accountId;
+
+ private String oldAccountId;
+
+ private String xmlAttributes;
+
+ private String resource;
+
+ private String objectClassName;
+
+ private SubjectType subjectType;
+
+ private Long subjectId;
+
+ public String getAccountId() {
+ return accountId;
+ }
+
+ public void setAccountId(final String accountId) {
+ this.accountId = accountId;
+ }
+
+ public String getOldAccountId() {
+ return oldAccountId;
+ }
+
+ public void setOldAccountId(final String oldAccountId) {
+ this.oldAccountId = oldAccountId;
+ }
+
+ public PropagationMode getPropagationMode() {
+ return propagationMode;
+ }
+
+ public void setPropagationMode(final PropagationMode propagationMode) {
+ this.propagationMode = propagationMode;
+ }
+
+ public String getResource() {
+ return resource;
+ }
+
+ public void setResource(final String resource) {
+ this.resource = resource;
+ }
+
+ public ResourceOperation getPropagationOperation() {
+ return propagationOperation;
+ }
+
+ public void setPropagationOperation(final ResourceOperation propagationOperation) {
+
+ this.propagationOperation = propagationOperation;
+ }
+
+ public String getXmlAttributes() {
+ return xmlAttributes;
+ }
+
+ public void setXmlAttributes(final String xmlAttributes) {
+ this.xmlAttributes = xmlAttributes;
+ }
+
+ public String getObjectClassName() {
+ return objectClassName;
+ }
+
+ public void setObjectClassName(final String objectClassName) {
+ this.objectClassName = objectClassName;
+ }
+
+ public SubjectType getSubjectType() {
+ return subjectType;
+ }
+
+ public void setSubjectType(final SubjectType subjectType) {
+ this.subjectType = subjectType;
+ }
+
+ public Long getSubjectId() {
+ return subjectId;
+ }
+
+ public void setSubjectId(final Long subjectId) {
+ this.subjectId = subjectId;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PushTaskTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PushTaskTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PushTaskTO.java
new file mode 100644
index 0000000..13d2ff4
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/PushTaskTO.java
@@ -0,0 +1,49 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "pushTask")
+@XmlType
+public class PushTaskTO extends AbstractProvisioningTaskTO {
+
+ private static final long serialVersionUID = -2143537546915809018L;
+
+ private String userFilter;
+
+ private String roleFilter;
+
+ public String getUserFilter() {
+ return userFilter;
+ }
+
+ public void setUserFilter(final String filter) {
+ this.userFilter = filter;
+ }
+
+ public String getRoleFilter() {
+ return roleFilter;
+ }
+
+ public void setRoleFilter(final String roleFilter) {
+ this.roleFilter = roleFilter;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReportExecTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReportExecTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReportExecTO.java
new file mode 100644
index 0000000..ef92b3b
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReportExecTO.java
@@ -0,0 +1,40 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "reportExec")
+@XmlType
+public class ReportExecTO extends AbstractExecTO {
+
+ private static final long serialVersionUID = -1025555939724089215L;
+
+ private long report;
+
+ public long getReport() {
+ return report;
+ }
+
+ public void setReport(long report) {
+ this.report = report;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReportTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReportTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReportTO.java
new file mode 100644
index 0000000..a8ae1ac
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ReportTO.java
@@ -0,0 +1,151 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.report.AbstractReportletConf;
+
+@XmlRootElement(name = "report")
+@XmlType
+public class ReportTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 5274568072084814410L;
+
+ private long id;
+
+ private String name;
+
+ private List<AbstractReportletConf> reportletConfs = new ArrayList<>();
+
+ private String cronExpression;
+
+ private List<ReportExecTO> executions = new ArrayList<>();
+
+ private String latestExecStatus;
+
+ private Date lastExec;
+
+ private Date nextExec;
+
+ private Date startDate;
+
+ private Date endDate;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ @XmlElementWrapper(name = "reportletConfs")
+ @XmlElement(name = "reportletConf")
+ @JsonProperty("reportletConfs")
+ public List<AbstractReportletConf> getReportletConfs() {
+ return reportletConfs;
+ }
+
+ public String getCronExpression() {
+ return cronExpression;
+ }
+
+ public void setCronExpression(final String cronExpression) {
+ this.cronExpression = cronExpression;
+ }
+
+ @XmlElementWrapper(name = "executions")
+ @XmlElement(name = "execution")
+ @JsonProperty("executions")
+ public List<ReportExecTO> getExecutions() {
+ return executions;
+ }
+
+ public String getLatestExecStatus() {
+ return latestExecStatus;
+ }
+
+ public void setLatestExecStatus(final String latestExecStatus) {
+ this.latestExecStatus = latestExecStatus;
+ }
+
+ public Date getLastExec() {
+ return lastExec == null
+ ? null
+ : new Date(lastExec.getTime());
+ }
+
+ public void setLastExec(final Date lastExec) {
+ if (lastExec != null) {
+ this.lastExec = new Date(lastExec.getTime());
+ }
+ }
+
+ public Date getNextExec() {
+ return nextExec == null
+ ? null
+ : new Date(nextExec.getTime());
+ }
+
+ public void setNextExec(final Date nextExec) {
+ if (nextExec != null) {
+ this.nextExec = new Date(nextExec.getTime());
+ }
+ }
+
+ public Date getStartDate() {
+ return startDate == null
+ ? null
+ : new Date(startDate.getTime());
+ }
+
+ public void setStartDate(final Date startDate) {
+ if (startDate != null) {
+ this.startDate = new Date(startDate.getTime());
+ }
+ }
+
+ public Date getEndDate() {
+ return endDate == null
+ ? null
+ : new Date(endDate.getTime());
+ }
+
+ public void setEndDate(final Date endDate) {
+ if (endDate != null) {
+ this.endDate = new Date(endDate.getTime());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ResourceTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ResourceTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ResourceTO.java
new file mode 100644
index 0000000..98f33d2
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/ResourceTO.java
@@ -0,0 +1,270 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.common.lib.types.PropagationMode;
+import org.apache.syncope.common.lib.types.TraceLevel;
+
+@XmlRootElement(name = "resource")
+@XmlType
+public class ResourceTO extends AbstractAnnotatedBean {
+
+ private static final long serialVersionUID = -9193551354041698963L;
+
+ /**
+ * The resource identifier is the name.
+ */
+ private String name;
+
+ /**
+ * The resource type is identified by the associated connector.
+ */
+ private Long connectorId;
+
+ /**
+ * Convenience information: display name for the connector id.
+ */
+ private String connectorDisplayName;
+
+ private MappingTO umapping;
+
+ private MappingTO rmapping;
+
+ private boolean propagationPrimary;
+
+ private int propagationPriority;
+
+ private boolean randomPwdIfNotProvided;
+
+ private PropagationMode propagationMode;
+
+ private boolean enforceMandatoryCondition;
+
+ private TraceLevel createTraceLevel;
+
+ private TraceLevel updateTraceLevel;
+
+ private TraceLevel deleteTraceLevel;
+
+ private TraceLevel syncTraceLevel;
+
+ private Long passwordPolicy;
+
+ private Long accountPolicy;
+
+ private Long syncPolicy;
+
+ private Set<ConnConfProperty> connConfProperties;
+
+ private String usyncToken;
+
+ private String rsyncToken;
+
+ private List<String> propagationActionsClassNames = new ArrayList<>();
+
+ public ResourceTO() {
+ super();
+
+ connConfProperties = new HashSet<>();
+ propagationMode = PropagationMode.TWO_PHASES;
+ propagationPriority = 0;
+
+ createTraceLevel = TraceLevel.ALL;
+ updateTraceLevel = TraceLevel.ALL;
+ deleteTraceLevel = TraceLevel.ALL;
+ syncTraceLevel = TraceLevel.ALL;
+ }
+
+ public String getKey() {
+ return name;
+ }
+
+ public void setKey(final String key) {
+ this.name = key;
+ }
+
+ public boolean isEnforceMandatoryCondition() {
+ return enforceMandatoryCondition;
+ }
+
+ public void setEnforceMandatoryCondition(final boolean enforceMandatoryCondition) {
+ this.enforceMandatoryCondition = enforceMandatoryCondition;
+ }
+
+ public Long getConnectorId() {
+ return connectorId;
+ }
+
+ public void setConnectorId(final Long connectorId) {
+ this.connectorId = connectorId;
+ }
+
+ public String getConnectorDisplayName() {
+ return connectorDisplayName;
+ }
+
+ public void setConnectorDisplayName(final String connectorDisplayName) {
+ this.connectorDisplayName = connectorDisplayName;
+ }
+
+ public MappingTO getUmapping() {
+ return umapping;
+ }
+
+ public void setUmapping(final MappingTO umapping) {
+ this.umapping = umapping;
+ }
+
+ public MappingTO getRmapping() {
+ return rmapping;
+ }
+
+ public void setRmapping(final MappingTO rmapping) {
+ this.rmapping = rmapping;
+ }
+
+ public boolean isPropagationPrimary() {
+ return propagationPrimary;
+ }
+
+ public void setPropagationPrimary(final boolean propagationPrimary) {
+ this.propagationPrimary = propagationPrimary;
+ }
+
+ public int getPropagationPriority() {
+ return propagationPriority;
+ }
+
+ public void setPropagationPriority(final int propagationPriority) {
+ this.propagationPriority = propagationPriority;
+ }
+
+ public boolean isRandomPwdIfNotProvided() {
+ return randomPwdIfNotProvided;
+ }
+
+ public void setRandomPwdIfNotProvided(final boolean randomPwdIfNotProvided) {
+ this.randomPwdIfNotProvided = randomPwdIfNotProvided;
+ }
+
+ public PropagationMode getPropagationMode() {
+ return propagationMode;
+ }
+
+ public void setPropagationMode(final PropagationMode propagationMode) {
+ this.propagationMode = propagationMode;
+ }
+
+ public TraceLevel getCreateTraceLevel() {
+ return createTraceLevel;
+ }
+
+ public void setCreateTraceLevel(final TraceLevel createTraceLevel) {
+ this.createTraceLevel = createTraceLevel;
+ }
+
+ public TraceLevel getDeleteTraceLevel() {
+ return deleteTraceLevel;
+ }
+
+ public void setDeleteTraceLevel(final TraceLevel deleteTraceLevel) {
+ this.deleteTraceLevel = deleteTraceLevel;
+ }
+
+ public TraceLevel getUpdateTraceLevel() {
+ return updateTraceLevel;
+ }
+
+ public void setUpdateTraceLevel(final TraceLevel updateTraceLevel) {
+ this.updateTraceLevel = updateTraceLevel;
+ }
+
+ public Long getPasswordPolicy() {
+ return passwordPolicy;
+ }
+
+ public void setPasswordPolicy(final Long passwordPolicy) {
+ this.passwordPolicy = passwordPolicy;
+ }
+
+ public Long getAccountPolicy() {
+ return accountPolicy;
+ }
+
+ public void setAccountPolicy(final Long accountPolicy) {
+ this.accountPolicy = accountPolicy;
+ }
+
+ public Long getSyncPolicy() {
+ return syncPolicy;
+ }
+
+ public void setSyncPolicy(final Long syncPolicy) {
+ this.syncPolicy = syncPolicy;
+ }
+
+ @XmlElementWrapper(name = "connConfProperties")
+ @XmlElement(name = "property")
+ @JsonProperty("connConfProperties")
+ public Set<ConnConfProperty> getConnConfProperties() {
+ return connConfProperties;
+ }
+
+ public TraceLevel getSyncTraceLevel() {
+ return syncTraceLevel;
+ }
+
+ public void setSyncTraceLevel(final TraceLevel syncTraceLevel) {
+ this.syncTraceLevel = syncTraceLevel;
+ }
+
+ public String getUsyncToken() {
+ return usyncToken;
+ }
+
+ public void setUsyncToken(final String syncToken) {
+ this.usyncToken = syncToken;
+ }
+
+ public String getRsyncToken() {
+ return rsyncToken;
+ }
+
+ public void setRsyncToken(final String syncToken) {
+ this.rsyncToken = syncToken;
+ }
+
+ @XmlElementWrapper(name = "propagationActionsClassNames")
+ @XmlElement(name = "propagationActionsClassName")
+ @JsonProperty("propagationActionsClassNames")
+ public List<String> getPropagationActionsClassNames() {
+ return propagationActionsClassNames;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
index 79ddfb3..6e24929 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/RoleTO.java
@@ -239,7 +239,7 @@ public class RoleTO extends AbstractSubjectTO {
}
public String getDisplayName() {
- return getId() + " " + getName();
+ return getKey() + " " + getName();
}
public static long fromDisplayName(final String displayName) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SchedTaskTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SchedTaskTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SchedTaskTO.java
new file mode 100644
index 0000000..330a12d
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SchedTaskTO.java
@@ -0,0 +1,101 @@
+/*
+ * 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.common.lib.to;
+
+import java.util.Date;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "schedTask")
+@XmlType
+@XmlSeeAlso(AbstractProvisioningTaskTO.class)
+public class SchedTaskTO extends AbstractTaskTO {
+
+ private static final long serialVersionUID = -5722284116974636425L;
+
+ private String cronExpression;
+
+ private String jobClassName;
+
+ private String name;
+
+ private String description;
+
+ private Date lastExec;
+
+ private Date nextExec;
+
+ public String getCronExpression() {
+ return cronExpression;
+ }
+
+ public void setCronExpression(final String cronExpression) {
+ this.cronExpression = cronExpression;
+ }
+
+ public String getJobClassName() {
+ return jobClassName;
+ }
+
+ public void setJobClassName(final String jobClassName) {
+ this.jobClassName = jobClassName;
+ }
+
+ public Date getLastExec() {
+ return lastExec == null
+ ? null
+ : new Date(lastExec.getTime());
+ }
+
+ public void setLastExec(final Date lastExec) {
+ if (lastExec != null) {
+ this.lastExec = new Date(lastExec.getTime());
+ }
+ }
+
+ public Date getNextExec() {
+ return nextExec == null
+ ? null
+ : new Date(nextExec.getTime());
+ }
+
+ public void setNextExec(final Date nextExec) {
+ if (nextExec != null) {
+ this.nextExec = new Date(nextExec.getTime());
+ }
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SecurityQuestionTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SecurityQuestionTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SecurityQuestionTO.java
new file mode 100644
index 0000000..dd73f2c
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SecurityQuestionTO.java
@@ -0,0 +1,51 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlRootElement(name = "securityQuestion")
+@XmlType
+public class SecurityQuestionTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 5969810939993556530L;
+
+ private long key;
+
+ private String content;
+
+ public long getKey() {
+ return key;
+ }
+
+ public void setKey(final long key) {
+ this.key = key;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(final String content) {
+ this.content = content;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncPolicyTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncPolicyTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncPolicyTO.java
new file mode 100644
index 0000000..4edcc43
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncPolicyTO.java
@@ -0,0 +1,54 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.syncope.common.lib.types.SyncPolicySpec;
+
+@XmlRootElement(name = "syncPolicy")
+@XmlType
+public class SyncPolicyTO extends AbstractPolicyTO {
+
+ private static final long serialVersionUID = 993024634238024242L;
+
+ private SyncPolicySpec specification;
+
+ public SyncPolicyTO() {
+ this(false);
+ }
+
+ public SyncPolicyTO(final boolean global) {
+ super();
+
+ PolicyType type = global
+ ? PolicyType.GLOBAL_SYNC
+ : PolicyType.SYNC;
+ setType(type);
+ }
+
+ public void setSpecification(final SyncPolicySpec specification) {
+ this.specification = specification;
+ }
+
+ public SyncPolicySpec getSpecification() {
+ return specification;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncTaskTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncTaskTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncTaskTO.java
new file mode 100644
index 0000000..9e33e96
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/SyncTaskTO.java
@@ -0,0 +1,59 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "syncTask")
+@XmlType
+public class SyncTaskTO extends AbstractProvisioningTaskTO {
+
+ private static final long serialVersionUID = -2143537546915809017L;
+
+ private UserTO userTemplate;
+
+ private RoleTO roleTemplate;
+
+ private boolean fullReconciliation;
+
+ public UserTO getUserTemplate() {
+ return userTemplate;
+ }
+
+ public void setUserTemplate(final UserTO userTemplate) {
+ this.userTemplate = userTemplate;
+ }
+
+ public RoleTO getRoleTemplate() {
+ return roleTemplate;
+ }
+
+ public void setRoleTemplate(final RoleTO roleTemplate) {
+ this.roleTemplate = roleTemplate;
+ }
+
+ public boolean isFullReconciliation() {
+ return fullReconciliation;
+ }
+
+ public void setFullReconciliation(boolean fullReconciliation) {
+ this.fullReconciliation = fullReconciliation;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/TaskExecTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/TaskExecTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/TaskExecTO.java
new file mode 100644
index 0000000..467c35e
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/TaskExecTO.java
@@ -0,0 +1,39 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "taskExec")
+@XmlType
+public class TaskExecTO extends AbstractExecTO {
+
+ private static final long serialVersionUID = -5401795154606268973L;
+
+ private long task;
+
+ public long getTask() {
+ return task;
+ }
+
+ public void setTask(final long task) {
+ this.task = task;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/VirSchemaTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/VirSchemaTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/VirSchemaTO.java
new file mode 100644
index 0000000..1a9d3bd
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/VirSchemaTO.java
@@ -0,0 +1,38 @@
+/*
+ * 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.common.lib.to;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(name = "virtualSchema")
+public class VirSchemaTO extends AbstractSchemaTO {
+
+ private static final long serialVersionUID = -8198557479659701343L;
+
+ private boolean readonly;
+
+ public boolean isReadonly() {
+ return readonly;
+ }
+
+ public void setReadonly(final boolean readonly) {
+ this.readonly = readonly;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormPropertyTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormPropertyTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormPropertyTO.java
new file mode 100644
index 0000000..c89bfcd
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormPropertyTO.java
@@ -0,0 +1,119 @@
+/*
+ * 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.common.lib.to;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.types.WorkflowFormPropertyType;
+
+@XmlRootElement(name = "workflowFormProperty")
+@XmlType
+public class WorkflowFormPropertyTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 9139969592634304261L;
+
+ private String key;
+
+ private String name;
+
+ private WorkflowFormPropertyType type;
+
+ private String value;
+
+ private boolean readable;
+
+ private boolean writable;
+
+ private boolean required;
+
+ private String datePattern;
+
+ private Map<String, String> enumValues = new HashMap<>();
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(final String key) {
+ this.key = key;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public boolean isReadable() {
+ return readable;
+ }
+
+ public void setReadable(final boolean readable) {
+ this.readable = readable;
+ }
+
+ public boolean isRequired() {
+ return required;
+ }
+
+ public void setRequired(final boolean required) {
+ this.required = required;
+ }
+
+ public WorkflowFormPropertyType getType() {
+ return type;
+ }
+
+ public void setType(final WorkflowFormPropertyType type) {
+ this.type = type;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(final String value) {
+ this.value = value;
+ }
+
+ public boolean isWritable() {
+ return writable;
+ }
+
+ public void setWritable(final boolean writable) {
+ this.writable = writable;
+ }
+
+ public String getDatePattern() {
+ return datePattern;
+ }
+
+ public void setDatePattern(final String datePattern) {
+ this.datePattern = datePattern;
+ }
+
+ public Map<String, String> getEnumValues() {
+ return enumValues;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormTO.java
new file mode 100644
index 0000000..f63d9fe
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormTO.java
@@ -0,0 +1,162 @@
+/*
+ * 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.common.lib.to;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlRootElement(name = "workflowForm")
+@XmlType
+public class WorkflowFormTO extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -7044543391316529128L;
+
+ private long userKey;
+
+ private String taskId;
+
+ private String key;
+
+ private String description;
+
+ private Date createTime;
+
+ private Date dueDate;
+
+ private String owner;
+
+ private final List<WorkflowFormPropertyTO> properties;
+
+ public WorkflowFormTO() {
+ properties = new ArrayList<>();
+ }
+
+ public long getUserKey() {
+ return userKey;
+ }
+
+ public void setUserKey(long userKey) {
+ this.userKey = userKey;
+ }
+
+ public String getTaskId() {
+ return taskId;
+ }
+
+ public void setTaskId(final String taskId) {
+ this.taskId = taskId;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(final String key) {
+ this.key = key;
+ }
+
+ public Date getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(final Date createTime) {
+ this.createTime = createTime;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ public Date getDueDate() {
+ return dueDate;
+ }
+
+ public void setDueDate(final Date dueDate) {
+ this.dueDate = dueDate;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ public void setOwner(final String owner) {
+ this.owner = owner;
+ }
+
+ @XmlElementWrapper(name = "workflowFormProperties")
+ @XmlElement(name = "workflowFormProperty")
+ @JsonProperty("workflowFormProperties")
+ public List<WorkflowFormPropertyTO> getProperties() {
+ return properties;
+ }
+
+ public boolean addProperty(final WorkflowFormPropertyTO property) {
+ return properties.contains(property)
+ ? true
+ : properties.add(property);
+ }
+
+ public boolean removeProperty(final WorkflowFormPropertyTO property) {
+ return properties.remove(property);
+ }
+
+ @JsonIgnore
+ public Map<String, WorkflowFormPropertyTO> getPropertyMap() {
+ Map<String, WorkflowFormPropertyTO> result;
+
+ if (getProperties() == null) {
+ result = Collections.emptyMap();
+ } else {
+ result = new HashMap<>();
+ for (WorkflowFormPropertyTO prop : getProperties()) {
+ result.put(prop.getKey(), prop);
+ }
+ result = Collections.unmodifiableMap(result);
+ }
+
+ return result;
+ }
+
+ @JsonIgnore
+ public Map<String, String> getPropertiesForSubmit() {
+ Map<String, String> props = new HashMap<String, String>();
+ for (WorkflowFormPropertyTO prop : getProperties()) {
+ if (prop.isWritable()) {
+ props.put(prop.getKey(), prop.getValue());
+ }
+ }
+
+ return props;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/package-info.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/package-info.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/package-info.java
new file mode 100644
index 0000000..b02ed8f
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/to/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@XmlSchema(namespace = SyncopeConstants.NAMESPACE)
+package org.apache.syncope.common.lib.to;
+
+import javax.xml.bind.annotation.XmlSchema;
+import org.apache.syncope.common.lib.SyncopeConstants;
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditElements.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditElements.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditElements.java
new file mode 100644
index 0000000..40ff86a
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditElements.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.common.lib.types;
+
+import java.io.Serializable;
+import javax.xml.bind.annotation.XmlEnum;
+import org.apache.commons.lang3.StringUtils;
+
+public final class AuditElements implements Serializable {
+
+ private static final long serialVersionUID = -4385059255522273254L;
+
+ private AuditElements() {
+ }
+
+ @XmlEnum
+ public enum EventCategoryType {
+
+ REST(StringUtils.EMPTY),
+ TASK(StringUtils.EMPTY),
+ PROPAGATION("PropagationTask"),
+ SYNCHRONIZATION("SyncTask"),
+ PUSH("PushTask"),
+ CUSTOM(StringUtils.EMPTY);
+
+ private final String value;
+
+ EventCategoryType(final String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+ }
+
+ @XmlEnum
+ public enum Result {
+
+ SUCCESS,
+ FAILURE
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java
new file mode 100644
index 0000000..2e385fc
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/AuditLoggerName.java
@@ -0,0 +1,222 @@
+/*
+ * 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.common.lib.types;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.text.ParseException;
+import java.util.AbstractMap;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.to.EventCategoryTO;
+import org.apache.syncope.common.lib.types.AuditElements.EventCategoryType;
+import org.apache.syncope.common.lib.types.AuditElements.Result;
+
+public class AuditLoggerName extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -647989486671786839L;
+
+ private final AuditElements.EventCategoryType type;
+
+ private final String category;
+
+ private final String subcategory;
+
+ private final String event;
+
+ private final Result result;
+
+ @JsonCreator
+ public AuditLoggerName(
+ @JsonProperty("type") final AuditElements.EventCategoryType type,
+ @JsonProperty("category") final String category,
+ @JsonProperty("subcategory") final String subcategory,
+ @JsonProperty("event") final String event,
+ @JsonProperty("result") final Result result)
+ throws IllegalArgumentException {
+
+ this.type = type == null ? AuditElements.EventCategoryType.CUSTOM : type;
+ this.category = category;
+ this.subcategory = subcategory;
+ this.event = event;
+ this.result = result == null ? Result.SUCCESS : result;
+ }
+
+ public AuditElements.EventCategoryType getType() {
+ return type;
+ }
+
+ public String getEvent() {
+ return event;
+ }
+
+ public String getCategory() {
+ return category;
+ }
+
+ public Result getResult() {
+ return result;
+ }
+
+ public String getSubcategory() {
+ return subcategory;
+ }
+
+ public String toLoggerName() {
+ return new StringBuilder().append(LoggerType.AUDIT.getPrefix()).append('.').
+ append(buildEvent(type, category, subcategory, event, result)).toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static AuditLoggerName fromLoggerName(final String loggerName)
+ throws IllegalArgumentException, ParseException {
+
+ if (StringUtils.isBlank(loggerName)) {
+ throw new IllegalArgumentException("Null value not permitted");
+ }
+
+ if (!loggerName.startsWith(LoggerType.AUDIT.getPrefix())) {
+ throw new ParseException("Audit logger name must start with " + LoggerType.AUDIT.getPrefix(), 0);
+ }
+
+ final Map.Entry<EventCategoryTO, Result> eventCategory = parseEventCategory(
+ loggerName.replaceAll(LoggerType.AUDIT.getPrefix() + ".", ""));
+
+ return new AuditLoggerName(
+ eventCategory.getKey().getType(),
+ eventCategory.getKey().getCategory(),
+ eventCategory.getKey().getSubcategory(),
+ eventCategory.getKey().getEvents().isEmpty()
+ ? StringUtils.EMPTY : eventCategory.getKey().getEvents().iterator().next(),
+ eventCategory.getValue());
+ }
+
+ private static Map.Entry<EventCategoryTO, Result> parseEventCategory(final String event) {
+ final EventCategoryTO eventCategoryTO = new EventCategoryTO();
+
+ Result condition = null;
+
+ if (StringUtils.isNotEmpty(event)) {
+ final String[] elements = event.substring(1, event.length() - 1).split("\\]:\\[");
+
+ if (elements.length == 1) {
+ eventCategoryTO.setType(EventCategoryType.CUSTOM);
+ condition = Result.SUCCESS;
+ eventCategoryTO.getEvents().add(event);
+ } else {
+ EventCategoryType type;
+
+ if (EventCategoryType.PROPAGATION.toString().equals(elements[0])) {
+ type = EventCategoryType.PROPAGATION;
+ } else if (EventCategoryType.SYNCHRONIZATION.toString().equals(elements[0])) {
+ type = EventCategoryType.SYNCHRONIZATION;
+ } else if (EventCategoryType.PUSH.toString().equals(elements[0])) {
+ type = EventCategoryType.PUSH;
+ } else {
+ try {
+ type = EventCategoryType.valueOf(elements[0]);
+ } catch (Exception e) {
+ type = EventCategoryType.CUSTOM;
+ }
+ }
+
+ eventCategoryTO.setType(type);
+
+ eventCategoryTO.setCategory(StringUtils.isNotEmpty(elements[1]) ? elements[1] : null);
+
+ eventCategoryTO.setSubcategory(StringUtils.isNotEmpty(elements[2]) ? elements[2] : null);
+
+ if (elements.length > 3 && StringUtils.isNotEmpty(elements[3])) {
+ eventCategoryTO.getEvents().add(elements[3]);
+ }
+
+ if (elements.length > 4) {
+ condition = Result.valueOf(elements[4].toUpperCase());
+ }
+ }
+ }
+
+ return new AbstractMap.SimpleEntry< EventCategoryTO, Result>(eventCategoryTO, condition);
+ }
+
+ /**
+ * Build event string with the following syntax [type]:[category]:[subcategory]:[event]:[maybe result value cond].
+ *
+ * @param type event type.
+ * @param category event category.
+ * @param subcategory event subcategory.
+ * @param event event.
+ * @param resultValueCondition result value condition.
+ * @return event string.
+ */
+ public static String buildEvent(
+ final AuditElements.EventCategoryType type,
+ final String category,
+ final String subcategory,
+ final String event,
+ final AuditElements.Result resultValueCondition) {
+
+ final StringBuilder eventBuilder = new StringBuilder();
+
+ eventBuilder.append('[');
+ if (type != null) {
+ if (StringUtils.isNotBlank(type.toString())) {
+ eventBuilder.append(type.toString());
+ } else {
+ eventBuilder.append(type.name());
+ }
+ }
+ eventBuilder.append(']');
+
+ eventBuilder.append(":");
+
+ eventBuilder.append('[');
+ if (StringUtils.isNotBlank(category)) {
+ eventBuilder.append(category);
+ }
+ eventBuilder.append(']');
+
+ eventBuilder.append(":");
+
+ eventBuilder.append('[');
+ if (StringUtils.isNotBlank(subcategory)) {
+ eventBuilder.append(subcategory);
+ }
+ eventBuilder.append(']');
+
+ eventBuilder.append(":");
+
+ eventBuilder.append('[');
+ if (StringUtils.isNotBlank(event)) {
+ eventBuilder.append(event);
+ }
+ eventBuilder.append(']');
+
+ if (resultValueCondition != null) {
+ eventBuilder.append(":");
+
+ eventBuilder.append('[');
+ eventBuilder.append(resultValueCondition);
+ eventBuilder.append(']');
+ }
+
+ return eventBuilder.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
new file mode 100644
index 0000000..0c272a9
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/ClientExceptionType.java
@@ -0,0 +1,107 @@
+/*
+ * 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.common.lib.types;
+
+import javax.ws.rs.core.Response;
+
+public enum ClientExceptionType {
+
+ AssociatedResources(Response.Status.BAD_REQUEST),
+ Composite(Response.Status.BAD_REQUEST),
+ ConcurrentModification(Response.Status.PRECONDITION_FAILED),
+ DataIntegrityViolation(Response.Status.BAD_REQUEST),
+ EntityExists(Response.Status.CONFLICT),
+ GenericPersistence(Response.Status.BAD_REQUEST),
+ InvalidSecurityAnswer(Response.Status.BAD_REQUEST),
+ InvalidLogger(Response.Status.BAD_REQUEST),
+ InvalidConnInstance(Response.Status.BAD_REQUEST),
+ InvalidConnIdConf(Response.Status.BAD_REQUEST),
+ InvalidPolicy(Response.Status.BAD_REQUEST),
+ InvalidSyncopeConf(Response.Status.BAD_REQUEST),
+ InvalidSyncopeRole(Response.Status.BAD_REQUEST),
+ InvalidReportExec(Response.Status.BAD_REQUEST),
+ InvalidRoles(Response.Status.BAD_REQUEST),
+ InvalidSchemaDefinition(Response.Status.BAD_REQUEST),
+ InvalidSearchExpression(Response.Status.BAD_REQUEST),
+ InvalidPageOrSize(Response.Status.BAD_REQUEST),
+ InvalidPropagationTaskExecReport(Response.Status.BAD_REQUEST),
+ InvalidUSchema(Response.Status.BAD_REQUEST),
+ InvalidUDerSchema(Response.Status.BAD_REQUEST),
+ InvalidUVirSchema(Response.Status.BAD_REQUEST),
+ InvalidRSchema(Response.Status.BAD_REQUEST),
+ InvalidRDerSchema(Response.Status.BAD_REQUEST),
+ InvalidRVirSchema(Response.Status.BAD_REQUEST),
+ InvalidMSchema(Response.Status.BAD_REQUEST),
+ InvalidMDerSchema(Response.Status.BAD_REQUEST),
+ InvalidMVirSchema(Response.Status.BAD_REQUEST),
+ InvalidCSchema(Response.Status.BAD_REQUEST),
+ InvalidSchemaMapping(Response.Status.BAD_REQUEST),
+ InvalidSyncopeUser(Response.Status.BAD_REQUEST),
+ InvalidExternalResource(Response.Status.BAD_REQUEST),
+ InvalidNotification(Response.Status.BAD_REQUEST),
+ InvalidPropagationTask(Response.Status.BAD_REQUEST),
+ InvalidSchedTask(Response.Status.BAD_REQUEST),
+ InvalidSyncTask(Response.Status.BAD_REQUEST),
+ InvalidPushTask(Response.Status.BAD_REQUEST),
+ InvalidValues(Response.Status.BAD_REQUEST),
+ NotFound(Response.Status.NOT_FOUND),
+ RejectedUserCreate(Response.Status.BAD_REQUEST),
+ RequiredValuesMissing(Response.Status.BAD_REQUEST),
+ RESTValidation(Response.Status.BAD_REQUEST),
+ RoleOwnership(Response.Status.BAD_REQUEST),
+ Scheduling(Response.Status.BAD_REQUEST),
+ UnauthorizedRole(Response.Status.UNAUTHORIZED),
+ Unauthorized(Response.Status.UNAUTHORIZED),
+ Unknown(Response.Status.BAD_REQUEST),
+ Workflow(Response.Status.BAD_REQUEST);
+
+ private final Response.Status responseStatus;
+
+ private ClientExceptionType(final Response.Status responseStatus) {
+ this.responseStatus = responseStatus;
+ }
+
+ public static ClientExceptionType fromHeaderValue(final String exceptionTypeHeaderValue) {
+ ClientExceptionType result = null;
+ for (ClientExceptionType type : values()) {
+ if (exceptionTypeHeaderValue.equals(type.getHeaderValue())) {
+ result = type;
+ }
+ }
+
+ if (result == null) {
+ throw new IllegalArgumentException("Unexpected header value: " + exceptionTypeHeaderValue);
+ }
+
+ return result;
+ }
+
+ public String getHeaderValue() {
+ return name();
+ }
+
+ public String getInfoHeaderValue(final String value) {
+ return getHeaderValue() + ":" + value;
+ }
+
+ public Response.Status getResponseStatus() {
+ return responseStatus;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/PolicyType.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/PolicyType.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/PolicyType.java
index a8f12f7..0b498d6 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/PolicyType.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/PolicyType.java
@@ -55,6 +55,10 @@ public enum PolicyType {
return description;
}
+ public boolean isGlobal() {
+ return name().startsWith("GLOBAL");
+ }
+
public static PolicyType fromString(final String value) {
return PolicyType.valueOf(value.toUpperCase());
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReportExecExportFormat.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReportExecExportFormat.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReportExecExportFormat.java
new file mode 100644
index 0000000..fdac43d
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/ReportExecExportFormat.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.types;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+@XmlEnum
+public enum ReportExecExportFormat {
+
+ XML,
+ HTML,
+ PDF,
+ RTF,
+ CSV
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/SchemaType.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/SchemaType.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/SchemaType.java
new file mode 100644
index 0000000..673666d
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/SchemaType.java
@@ -0,0 +1,68 @@
+/*
+ * 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.common.lib.types;
+
+import javax.xml.bind.annotation.XmlEnum;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.to.DerSchemaTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.VirSchemaTO;
+
+@XmlEnum
+public enum SchemaType {
+
+ /**
+ * Standard schema for normal attributes to be stored within syncope.
+ */
+ PLAIN(PlainSchemaTO.class),
+ /**
+ * Derived schema calculated based on other attributes.
+ */
+ DERIVED(DerSchemaTO.class),
+ /**
+ * Virtual schema for attributes fetched from remote resources only.
+ */
+ VIRTUAL(VirSchemaTO.class);
+
+ private final Class<? extends AbstractSchemaTO> toClass;
+
+ SchemaType(final Class<? extends AbstractSchemaTO> toClass) {
+ this.toClass = toClass;
+ }
+
+ public Class<? extends AbstractSchemaTO> getToClass() {
+ return toClass;
+ }
+
+ public static SchemaType fromToClass(final Class<? extends AbstractSchemaTO> toClass) {
+ SchemaType schemaType = null;
+
+ if (PlainSchemaTO.class.equals(toClass)) {
+ schemaType = SchemaType.PLAIN;
+ } else if (DerSchemaTO.class.equals(toClass)) {
+ schemaType = SchemaType.DERIVED;
+ } else if (VirSchemaTO.class.equals(toClass)) {
+ schemaType = SchemaType.VIRTUAL;
+ } else {
+ throw new IllegalArgumentException("Unexpected class: " + toClass.getName());
+ }
+
+ return schemaType;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/WorkflowFormPropertyType.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/WorkflowFormPropertyType.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/WorkflowFormPropertyType.java
new file mode 100644
index 0000000..ec2db4a
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/WorkflowFormPropertyType.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.common.lib.types;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+@XmlEnum
+public enum WorkflowFormPropertyType {
+
+ String,
+ Long,
+ Enum,
+ Date,
+ Boolean
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/WorkflowTasks.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/WorkflowTasks.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/WorkflowTasks.java
new file mode 100644
index 0000000..8c487f8
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/types/WorkflowTasks.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.common.lib.types;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class WorkflowTasks {
+
+ private List<String> tasks;
+
+ public WorkflowTasks() {
+ this.tasks = new ArrayList<String>();
+ }
+
+ public WorkflowTasks(final Collection<String> tasks) {
+ this();
+ this.tasks.addAll(tasks);
+ }
+
+ public List<String> getTasks() {
+ return tasks;
+ }
+
+ public void setTasks(final List<String> tasks) {
+ this.tasks = tasks;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/AbstractWrappable.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/AbstractWrappable.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/AbstractWrappable.java
new file mode 100644
index 0000000..7ba0afa
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/AbstractWrappable.java
@@ -0,0 +1,46 @@
+/*
+ * 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.common.lib.wrap;
+
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+public abstract class AbstractWrappable<E> extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 1712808704911635170L;
+
+ private E element;
+
+ public static <E, T extends AbstractWrappable<E>> T getInstance(final Class<T> reference, final E element) {
+ try {
+ T instance = reference.newInstance();
+ instance.setElement(element);
+ return instance;
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Could not instantiate " + reference.getName(), e);
+ }
+ }
+
+ public E getElement() {
+ return element;
+ }
+
+ public void setElement(final E element) {
+ this.element = element;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/CorrelationRuleClass.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/CorrelationRuleClass.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/CorrelationRuleClass.java
new file mode 100644
index 0000000..6a8997c
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/CorrelationRuleClass.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "correlationRuleClass")
+@XmlType
+public class CorrelationRuleClass extends AbstractWrappable<String> {
+
+ private static final long serialVersionUID = -6715106427060816725L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/EntitlementTO.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/EntitlementTO.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/EntitlementTO.java
new file mode 100644
index 0000000..62530eb
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/EntitlementTO.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "entitlement")
+@XmlType
+public class EntitlementTO extends AbstractWrappable<String> {
+
+ private static final long serialVersionUID = 7133614577172038452L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/JobClass.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/JobClass.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/JobClass.java
new file mode 100644
index 0000000..b85a6f5
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/JobClass.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "jobClass")
+@XmlType
+public class JobClass extends AbstractWrappable<String> {
+
+ private static final long serialVersionUID = -1953799905627918822L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/MailTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/MailTemplate.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/MailTemplate.java
new file mode 100644
index 0000000..11e254d
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/MailTemplate.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "mailTemplate")
+@XmlType
+public class MailTemplate extends AbstractWrappable<String> {
+
+ private static final long serialVersionUID = 7232619557172031478L;
+
+}
[13/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
[SYNCOPE-620] server logic in, tests missing
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/99369c31
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/99369c31
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/99369c31
Branch: refs/heads/2_0_X
Commit: 99369c3115b9feec77bebff5fbbb2813d72aedf5
Parents: fc8761c
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Jan 8 14:16:57 2015 +0100
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Jan 8 14:16:57 2015 +0100
----------------------------------------------------------------------
.../core/rest/controller/RoleController.java | 12 +-
syncope620/common/lib/pom.xml | 10 +
.../syncope/common/lib/AbstractBaseBean.java | 7 +-
.../common/lib/AttributableOperations.java | 508 ++++++++++
.../lib/SyncopeClientCompositeException.java | 96 ++
.../common/lib/SyncopeClientException.java | 97 ++
.../common/lib/mod/AbstractAttributableMod.java | 18 +-
.../syncope/common/lib/mod/MembershipMod.java | 46 +
.../syncope/common/lib/mod/ReferenceMod.java | 53 ++
.../common/lib/mod/ResourceAssociationMod.java | 80 ++
.../apache/syncope/common/lib/mod/RoleMod.java | 300 ++++++
.../syncope/common/lib/mod/StatusMod.java | 108 +++
.../apache/syncope/common/lib/mod/UserMod.java | 123 +++
.../syncope/common/lib/mod/package-info.java | 23 +
.../common/lib/report/RoleReportletConf.java | 2 +-
.../common/lib/report/UserReportletConf.java | 2 +-
.../common/lib/search/OrderByClauseBuilder.java | 45 +
.../search/RoleFiqlSearchConditionBuilder.java | 90 ++
.../syncope/common/lib/search/RoleProperty.java | 29 +
.../common/lib/search/SearchableFields.java | 67 ++
.../syncope/common/lib/search/SpecialAttr.java | 50 +
.../SyncopeFiqlSearchConditionBuilder.java | 110 +++
.../common/lib/search/SyncopeProperty.java | 37 +
.../search/UserFiqlSearchConditionBuilder.java | 95 ++
.../syncope/common/lib/search/UserProperty.java | 29 +
.../common/lib/to/AbstractAttributableTO.java | 10 +-
.../syncope/common/lib/to/AbstractExecTO.java | 87 ++
.../syncope/common/lib/to/AbstractPolicyTO.java | 89 ++
.../lib/to/AbstractProvisioningTaskTO.java | 117 +++
.../syncope/common/lib/to/AbstractSchemaTO.java | 44 +
.../syncope/common/lib/to/AbstractTaskTO.java | 98 ++
.../syncope/common/lib/to/AccountPolicyTO.java | 68 ++
.../syncope/common/lib/to/BulkAction.java | 70 ++
.../syncope/common/lib/to/BulkActionResult.java | 134 +++
.../apache/syncope/common/lib/to/ConfTO.java | 30 +
.../syncope/common/lib/to/ConnBundleTO.java | 95 ++
.../syncope/common/lib/to/ConnInstanceTO.java | 177 ++++
.../syncope/common/lib/to/DerSchemaTO.java | 39 +
.../apache/syncope/common/lib/to/ErrorTO.java | 66 ++
.../syncope/common/lib/to/EventCategoryTO.java | 89 ++
.../apache/syncope/common/lib/to/LoggerTO.java | 51 ++
.../syncope/common/lib/to/MappingItemTO.java | 134 +++
.../apache/syncope/common/lib/to/MappingTO.java | 120 +++
.../syncope/common/lib/to/NotificationTO.java | 175 ++++
.../common/lib/to/NotificationTaskTO.java | 105 +++
.../syncope/common/lib/to/PagedResult.java | 98 ++
.../syncope/common/lib/to/PasswordPolicyTO.java | 54 ++
.../syncope/common/lib/to/PlainSchemaTO.java | 156 ++++
.../common/lib/to/PropagationTaskTO.java | 123 +++
.../syncope/common/lib/to/PushTaskTO.java | 49 +
.../syncope/common/lib/to/ReportExecTO.java | 40 +
.../apache/syncope/common/lib/to/ReportTO.java | 151 +++
.../syncope/common/lib/to/ResourceTO.java | 270 ++++++
.../apache/syncope/common/lib/to/RoleTO.java | 2 +-
.../syncope/common/lib/to/SchedTaskTO.java | 101 ++
.../common/lib/to/SecurityQuestionTO.java | 51 ++
.../syncope/common/lib/to/SyncPolicyTO.java | 54 ++
.../syncope/common/lib/to/SyncTaskTO.java | 59 ++
.../syncope/common/lib/to/TaskExecTO.java | 39 +
.../syncope/common/lib/to/VirSchemaTO.java | 38 +
.../common/lib/to/WorkflowFormPropertyTO.java | 119 +++
.../syncope/common/lib/to/WorkflowFormTO.java | 162 ++++
.../syncope/common/lib/to/package-info.java | 23 +
.../syncope/common/lib/types/AuditElements.java | 61 ++
.../common/lib/types/AuditLoggerName.java | 222 +++++
.../common/lib/types/ClientExceptionType.java | 107 +++
.../syncope/common/lib/types/PolicyType.java | 4 +
.../lib/types/ReportExecExportFormat.java | 32 +
.../syncope/common/lib/types/SchemaType.java | 68 ++
.../lib/types/WorkflowFormPropertyType.java | 32 +
.../syncope/common/lib/types/WorkflowTasks.java | 47 +
.../common/lib/wrap/AbstractWrappable.java | 46 +
.../common/lib/wrap/CorrelationRuleClass.java | 30 +
.../syncope/common/lib/wrap/EntitlementTO.java | 30 +
.../syncope/common/lib/wrap/JobClass.java | 30 +
.../syncope/common/lib/wrap/MailTemplate.java | 30 +
.../common/lib/wrap/PropagationActionClass.java | 30 +
.../common/lib/wrap/PushActionClass.java | 30 +
.../common/lib/wrap/ReportletConfClass.java | 30 +
.../syncope/common/lib/wrap/ResourceName.java | 30 +
.../syncope/common/lib/wrap/SubjectId.java | 25 +
.../common/lib/wrap/SyncActionClass.java | 30 +
.../syncope/common/lib/wrap/Validator.java | 30 +
.../syncope/common/lib/wrap/package-info.java | 23 +
syncope620/pom.xml | 146 ++-
syncope620/server/logic/pom.xml | 127 +++
.../syncope/server/logic/AbstractLogic.java | 58 ++
.../logic/AbstractResourceAssociator.java | 37 +
.../server/logic/AbstractSubjectLogic.java | 43 +
.../logic/AbstractTransactionalLogic.java | 31 +
.../server/logic/ConfigurationLogic.java | 157 ++++
.../syncope/server/logic/ConnectorLogic.java | 341 +++++++
.../syncope/server/logic/EntitlementLogic.java | 58 ++
.../syncope/server/logic/LoggerLogic.java | 307 +++++++
.../server/logic/LogicInvocationHandler.java | 108 +++
.../server/logic/NotificationController.java | 127 +++
.../syncope/server/logic/PolicyController.java | 197 ++++
.../syncope/server/logic/ReportLogic.java | 348 +++++++
.../syncope/server/logic/ResourceLogic.java | 301 ++++++
.../apache/syncope/server/logic/RoleLogic.java | 405 ++++++++
.../syncope/server/logic/SchemaLogic.java | 328 +++++++
.../server/logic/SecurityQuestionLogic.java | 150 +++
.../apache/syncope/server/logic/TaskLogic.java | 408 +++++++++
.../logic/UnresolvedReferenceException.java | 35 +
.../apache/syncope/server/logic/UserLogic.java | 534 +++++++++++
.../syncope/server/logic/UserWorkflowLogic.java | 131 +++
.../syncope/server/logic/WorkflowLogic.java | 115 +++
.../logic/audit/AuditConnectionFactory.java | 159 ++++
.../server/logic/audit/AuditManager.java | 107 +++
.../data/AbstractAttributableDataBinder.java | 918 +++++++++++++++++++
.../logic/data/ConfigurationDataBinder.java | 75 ++
.../logic/data/ConnInstanceDataBinder.java | 246 +++++
.../logic/data/NotificationDataBinder.java | 62 ++
.../server/logic/data/PolicyDataBinder.java | 186 ++++
.../server/logic/data/ReportDataBinder.java | 175 ++++
.../server/logic/data/ResourceDataBinder.java | 389 ++++++++
.../server/logic/data/RoleDataBinder.java | 429 +++++++++
.../server/logic/data/SchemaDataBinder.java | 163 ++++
.../logic/data/SecurityQuestionDataBinder.java | 51 ++
.../server/logic/data/TaskDataBinder.java | 338 +++++++
.../server/logic/data/UserDataBinder.java | 479 ++++++++++
.../init/ImplementationClassNamesLoader.java | 141 +++
.../server/logic/init/JobInstanceLoader.java | 287 ++++++
.../logic/init/WorkflowAdapterLoader.java | 88 ++
.../logic/notification/NotificationJob.java | 280 ++++++
.../logic/notification/NotificationManager.java | 441 +++++++++
.../server/logic/report/AbstractReportlet.java | 66 ++
.../server/logic/report/ReportException.java | 32 +
.../syncope/server/logic/report/ReportJob.java | 206 +++++
.../server/logic/report/ReportXMLConst.java | 44 +
.../syncope/server/logic/report/Reportlet.java | 47 +
.../server/logic/report/ReportletConfClass.java | 32 +
.../server/logic/report/RoleReportlet.java | 327 +++++++
.../server/logic/report/StaticReportlet.java | 120 +++
.../server/logic/report/TextSerializer.java | 101 ++
.../server/logic/report/UserReportlet.java | 359 ++++++++
.../logic/search/SearchCondConverter.java | 50 +
.../server/logic/search/SearchCondVisitor.java | 203 ++++
.../persistence/api/dao/DuplicateException.java | 35 +
.../syncope/persistence/api/dao/RoleDAO.java | 2 +
.../syncope/persistence/api/dao/UserDAO.java | 3 +
.../api/entity/AttributableUtil.java | 5 +
.../api/entity/AttributableUtilFactory.java | 33 +
.../syncope/persistence/api/entity/Entity.java | 4 +-
.../persistence/api/entity/EntityFactory.java | 2 +
.../api/entity/ExternalResource.java | 2 +-
.../persistence/api/entity/role/Role.java | 4 +-
.../persistence/api/entity/task/TaskUtil.java | 36 +
.../api/entity/task/TaskUtilFactory.java | 33 +
syncope620/server/persistence-jpa/pom.xml | 2 +-
.../persistence/jpa/dao/AbstractSubjectDAO.java | 10 +-
.../syncope/persistence/jpa/dao/JPAConfDAO.java | 7 +-
.../syncope/persistence/jpa/dao/JPARoleDAO.java | 36 +-
.../jpa/dao/JPASubjectSearchDAO.java | 13 +-
.../syncope/persistence/jpa/dao/JPAUserDAO.java | 69 +-
.../persistence/jpa/entity/AbstractEntity.java | 5 +-
.../jpa/entity/JPAAttributableUtil.java | 103 +--
.../jpa/entity/JPAEntityFactory.java | 9 +-
.../persistence/jpa/entity/JPAPushPolicy.java | 2 +-
.../jpa/entity/JPASecurityQuestion.java | 2 +-
.../jpa/entity/JPAttributableUtilFactory.java | 85 ++
.../jpa/entity/conf/JPACPlainAttr.java | 2 +-
.../entity/conf/JPACPlainAttrUniqueValue.java | 2 +-
.../jpa/entity/conf/JPACPlainAttrValue.java | 2 +-
.../persistence/jpa/entity/conf/JPAConf.java | 2 +-
.../entity/membership/JPAMDerAttrTemplate.java | 2 +-
.../membership/JPAMPlainAttrTemplate.java | 2 +-
.../entity/membership/JPAMVirAttrTemplate.java | 2 +-
.../jpa/entity/role/JPARDerAttrTemplate.java | 2 +-
.../jpa/entity/role/JPARPlainAttrTemplate.java | 2 +-
.../jpa/entity/role/JPARVirAttrTemplate.java | 2 +-
.../persistence/jpa/entity/role/JPARole.java | 16 +-
.../jpa/entity/task/JPASchedTask.java | 2 +-
.../jpa/entity/task/JPATaskUtil.java | 132 +++
.../jpa/entity/task/JPATaskUtilFactory.java | 91 ++
.../persistence/jpa/entity/user/JPAUser.java | 8 +-
.../entity/ConnInstanceValidator.java | 2 +-
.../syncope/persistence/jpa/AbstractTest.java | 4 +
.../persistence/jpa/entity/AttrTest.java | 14 +-
.../persistence/jpa/entity/ConfTest.java | 4 +-
.../persistence/jpa/entity/DerSchemaTest.java | 4 +-
.../persistence/jpa/entity/PlainSchemaTest.java | 2 +-
.../persistence/jpa/entity/VirSchemaTest.java | 4 +-
.../persistence/jpa/relationship/AttrTest.java | 3 +-
.../jpa/relationship/DerSchemaTest.java | 3 +-
.../jpa/relationship/PlainSchemaTest.java | 7 +-
.../jpa/relationship/SecurityQuestionTest.java | 3 +
.../src/test/resources/content.xml | 26 +-
.../src/test/resources/persistenceTestEnv.xml | 5 +
syncope620/server/pom.xml | 5 +-
.../api/AttributableTransformer.java | 33 +
.../provisioning/api/ConnIdBundleManager.java | 284 ++++++
.../provisioning/api/ProvisioningManager.java | 42 +
.../api/RoleProvisioningManager.java | 37 +
.../syncope/provisioning/api/URIUtil.java | 61 ++
.../api/UserProvisioningManager.java | 57 ++
.../provisioning/api/WorkflowResult.java | 87 ++
.../provisioning/api/cache/VirAttrCache.java | 65 ++
.../provisioning/api/cache/VirAttrCacheKey.java | 79 ++
.../api/cache/VirAttrCacheValue.java | 86 ++
.../api/propagation/PropagationByResource.java | 365 ++++++++
.../api/propagation/PropagationException.java | 51 ++
.../api/propagation/PropagationManager.java | 248 +++++
.../api/propagation/PropagationReporter.java | 58 ++
.../propagation/PropagationTaskExecutor.java | 77 ++
.../api/sync/SyncCorrelationRule.java | 36 +
syncope620/server/provisioning-common/pom.xml | 44 +
.../common/cache/DisabledVirAttrCache.java | 52 ++
.../common/cache/MemoryVirAttrCache.java | 151 +++
.../server/security/SecureRandomUtil.java | 44 -
.../security/UnauthorizedRoleException.java | 42 +
syncope620/server/utils/pom.xml | 17 +-
.../syncope/server/utils/ConnObjectUtil.java | 764 +++++++++++++++
.../syncope/server/utils/ExceptionUtil.java | 47 +
.../InvalidPasswordPolicySpecException.java | 37 +
.../syncope/server/utils/MappingUtil.java | 736 +++++++++++++++
.../syncope/server/utils/PasswordGenerator.java | 320 +++++++
.../syncope/server/utils/SecureRandomUtil.java | 48 +
.../apache/syncope/server/utils/URIUtil.java | 61 --
.../serialization/UnwrappedObjectMapper.java | 95 ++
syncope620/server/workflow-api/pom.xml | 44 +
.../workflow/api/RoleWorkflowAdapter.java | 71 ++
.../workflow/api/UserWorkflowAdapter.java | 151 +++
.../server/workflow/api/WorkflowAdapter.java | 111 +++
.../workflow/api/WorkflowDefinitionFormat.java | 29 +
.../server/workflow/api/WorkflowException.java | 51 ++
.../workflow/api/WorkflowInstanceLoader.java | 28 +
.../server/workflow/api/package-info.java | 19 +
228 files changed, 22689 insertions(+), 280 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java b/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
index 3a0f9d6..9b1220e 100644
--- a/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
+++ b/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
@@ -18,13 +18,10 @@
*/
package org.apache.syncope.core.rest.controller;
-import static org.apache.syncope.core.rest.controller.AbstractController.LOG;
-
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -36,12 +33,10 @@ import org.apache.syncope.common.to.RoleTO;
import org.apache.syncope.common.types.ClientExceptionType;
import org.apache.syncope.common.SyncopeClientException;
import org.apache.syncope.common.to.PropagationStatus;
-import org.apache.syncope.core.provisioning.ProvisioningManager;
import org.apache.syncope.core.provisioning.RoleProvisioningManager;
import org.apache.syncope.common.reqres.BulkAction;
import org.apache.syncope.common.reqres.BulkActionResult;
import org.apache.syncope.common.types.SubjectType;
-import org.apache.syncope.core.persistence.beans.PropagationTask;
import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
import org.apache.syncope.core.persistence.dao.SubjectSearchDAO;
@@ -49,13 +44,10 @@ import org.apache.syncope.core.persistence.dao.NotFoundException;
import org.apache.syncope.core.persistence.dao.RoleDAO;
import org.apache.syncope.core.persistence.dao.UserDAO;
import org.apache.syncope.core.persistence.dao.search.OrderByClause;
-import org.apache.syncope.core.propagation.PropagationException;
-import org.apache.syncope.core.propagation.PropagationReporter;
import org.apache.syncope.core.propagation.PropagationTaskExecutor;
import org.apache.syncope.core.propagation.impl.PropagationManager;
import org.apache.syncope.core.rest.data.AttributableTransformer;
import org.apache.syncope.core.rest.data.RoleDataBinder;
-import org.apache.syncope.core.util.ApplicationContextProvider;
import org.apache.syncope.core.util.EntitlementUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -94,9 +86,9 @@ public class RoleController extends AbstractSubjectController<RoleTO, RoleMod> {
protected AttributableTransformer attrTransformer;
@Resource(name = "anonymousUser")
- private String anonymousUser;
+ protected String anonymousUser;
- @Resource(name = "roleProvisioningManager")
+ @Autowired
protected RoleProvisioningManager provisioningManager;
@PreAuthorize("hasAnyRole('ROLE_READ', T(org.apache.syncope.common.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/pom.xml b/syncope620/common/lib/pom.xml
index d52f136..ad51d98 100644
--- a/syncope620/common/lib/pom.xml
+++ b/syncope620/common/lib/pom.xml
@@ -35,6 +35,16 @@ under the License.
<dependencies>
<dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>javax.ws.rs-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-extension-search</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java
index 28bd4bd..8a6d9c4 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java
@@ -19,15 +19,20 @@
package org.apache.syncope.common.lib;
import java.io.Serializable;
+import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.ReportTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
@XmlType
// Reporting here only classes used via PagedResult
-//@XmlSeeAlso({ AbstractTaskTO.class, ReportTO.class, RoleTO.class, UserTO.class })
+@XmlSeeAlso({ AbstractTaskTO.class, ReportTO.class, RoleTO.class, UserTO.class })
public abstract class AbstractBaseBean implements Serializable {
private static final long serialVersionUID = 3119542005279892164L;
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
new file mode 100644
index 0000000..983cee4
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/AttributableOperations.java
@@ -0,0 +1,508 @@
+/*
+ * 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.common.lib;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.mod.AbstractAttributableMod;
+import org.apache.syncope.common.lib.mod.AbstractSubjectMod;
+import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.mod.MembershipMod;
+import org.apache.syncope.common.lib.mod.ReferenceMod;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+
+/**
+ * Utility class for manipulating classes extending AbstractAttributableTO and AbstractAttributableMod.
+ *
+ * @see AbstractAttributableTO
+ * @see AbstractAttributableMod
+ */
+public final class AttributableOperations {
+
+ private AttributableOperations() {
+ // empty constructor for static utility classes
+ }
+
+ private static void populate(final Map<String, AttrTO> updatedAttrs,
+ final Map<String, AttrTO> originalAttrs, final AbstractAttributableMod result) {
+
+ populate(updatedAttrs, originalAttrs, result, false);
+ }
+
+ private static void populate(final Map<String, AttrTO> updatedAttrs,
+ final Map<String, AttrTO> originalAttrs, final AbstractAttributableMod result,
+ final boolean virtuals) {
+
+ for (Map.Entry<String, AttrTO> entry : updatedAttrs.entrySet()) {
+ AttrMod mod = new AttrMod();
+ mod.setSchema(entry.getKey());
+
+ Set<String> updatedValues = new HashSet<String>(entry.getValue().getValues());
+
+ Set<String> originalValues = originalAttrs.containsKey(entry.getKey())
+ ? new HashSet<String>(originalAttrs.get(entry.getKey()).getValues())
+ : Collections.<String>emptySet();
+
+ if (!originalAttrs.containsKey(entry.getKey())) {
+ // SYNCOPE-459: take care of user virtual attributes without any value
+ updatedValues.remove("");
+ mod.getValuesToBeAdded().addAll(new ArrayList<String>(updatedValues));
+
+ if (virtuals) {
+ result.getVirAttrsToUpdate().add(mod);
+ } else {
+ result.getAttrsToUpdate().add(mod);
+ }
+ } else if (!updatedValues.equals(originalValues)) {
+ // avoid unwanted inputs
+ updatedValues.remove("");
+ if (!entry.getValue().isReadonly()) {
+ mod.getValuesToBeAdded().addAll(updatedValues);
+
+ if (!mod.isEmpty()) {
+ if (virtuals) {
+ result.getVirAttrsToRemove().add(mod.getSchema());
+ } else {
+ result.getAttrsToRemove().add(mod.getSchema());
+ }
+ }
+ }
+
+ mod.getValuesToBeRemoved().addAll(originalValues);
+
+ if (!mod.isEmpty()) {
+ if (virtuals) {
+ result.getVirAttrsToUpdate().add(mod);
+ } else {
+ result.getAttrsToUpdate().add(mod);
+ }
+ }
+ }
+ }
+ }
+
+ private static void diff(
+ final AbstractAttributableTO updated,
+ final AbstractAttributableTO original,
+ final AbstractAttributableMod result,
+ final boolean incremental) {
+
+ // 1. check same id
+ if (updated.getKey() != original.getKey()) {
+ throw new IllegalArgumentException("AttributableTO's id must be the same");
+ }
+ result.setKey(updated.getKey());
+
+ // 2. attributes
+ Map<String, AttrTO> updatedAttrs = new HashMap<>(updated.getAttrMap());
+ Map<String, AttrTO> originalAttrs = new HashMap<>(original.getAttrMap());
+
+ Set<String> originalAttrNames = new HashSet<>(originalAttrs.keySet());
+ originalAttrNames.removeAll(updatedAttrs.keySet());
+
+ if (!incremental) {
+ result.getAttrsToRemove().clear();
+ result.getAttrsToRemove().addAll(originalAttrNames);
+ }
+
+ Set<String> emptyUpdatedAttrs = new HashSet<>();
+ for (Map.Entry<String, AttrTO> entry : updatedAttrs.entrySet()) {
+ if (entry.getValue().getValues() == null || entry.getValue().getValues().isEmpty()) {
+
+ emptyUpdatedAttrs.add(entry.getKey());
+ }
+ }
+ for (String emptyUpdatedAttr : emptyUpdatedAttrs) {
+ updatedAttrs.remove(emptyUpdatedAttr);
+ result.getAttrsToRemove().add(emptyUpdatedAttr);
+ }
+
+ populate(updatedAttrs, originalAttrs, result);
+
+ // 3. derived attributes
+ updatedAttrs = updated.getDerAttrMap();
+ originalAttrs = original.getDerAttrMap();
+
+ originalAttrNames = new HashSet<>(originalAttrs.keySet());
+ originalAttrNames.removeAll(updatedAttrs.keySet());
+
+ if (!incremental) {
+ result.getDerAttrsToRemove().clear();
+ result.getDerAttrsToRemove().addAll(originalAttrNames);
+ }
+
+ Set<String> updatedAttrNames = new HashSet<>(updatedAttrs.keySet());
+ updatedAttrNames.removeAll(originalAttrs.keySet());
+ result.getDerAttrsToAdd().clear();
+ result.getDerAttrsToAdd().addAll(updatedAttrNames);
+
+ // 4. virtual attributes
+ updatedAttrs = updated.getVirAttrMap();
+ originalAttrs = original.getVirAttrMap();
+
+ originalAttrNames = new HashSet<>(originalAttrs.keySet());
+ originalAttrNames.removeAll(updatedAttrs.keySet());
+
+ if (!incremental) {
+ result.getVirAttrsToRemove().clear();
+ result.getVirAttrsToRemove().addAll(originalAttrNames);
+ }
+
+ populate(updatedAttrs, originalAttrs, result, true);
+
+ // 5. resources
+ if (original instanceof AbstractSubjectTO && updated instanceof AbstractSubjectTO
+ && result instanceof AbstractSubjectMod) {
+
+ Set<String> updatedRes = new HashSet<>(((AbstractSubjectTO) updated).getResources());
+ Set<String> originalRes = new HashSet<>(((AbstractSubjectTO) original).getResources());
+
+ updatedRes.removeAll(originalRes);
+ ((AbstractSubjectMod) result).getResourcesToAdd().clear();
+ ((AbstractSubjectMod) result).getResourcesToAdd().addAll(updatedRes);
+
+ originalRes.removeAll(((AbstractSubjectTO) updated).getResources());
+
+ if (!incremental) {
+ ((AbstractSubjectMod) result).getResourcesToRemove().clear();
+ ((AbstractSubjectMod) result).getResourcesToRemove().addAll(originalRes);
+ }
+ }
+ }
+
+ /**
+ * Calculate modifications needed by first in order to be equal to second.
+ *
+ * @param updated updated UserTO
+ * @param original original UserTO
+ * @return UserMod containing differences
+ */
+ public static UserMod diff(final UserTO updated, final UserTO original) {
+ return diff(updated, original, false);
+ }
+
+ /**
+ * Calculate modifications needed by first in order to be equal to second.
+ *
+ * @param updated updated UserTO
+ * @param original original UserTO
+ * @param incremental perform incremental diff (without removing existing info)
+ * @return UserMod containing differences
+ */
+ public static UserMod diff(final UserTO updated, final UserTO original, final boolean incremental) {
+ UserMod result = new UserMod();
+
+ diff(updated, original, result, incremental);
+
+ // 1. password
+ if (updated.getPassword() != null && (original.getPassword() == null
+ || !original.getPassword().equals(updated.getPassword()))) {
+
+ result.setPassword(updated.getPassword());
+ }
+
+ // 2. username
+ if (original.getUsername() != null && !original.getUsername().equals(updated.getUsername())) {
+ result.setUsername(updated.getUsername());
+ }
+
+ // 3. security question / answer
+ if (updated.getSecurityQuestion() == null) {
+ result.setSecurityQuestion(null);
+ result.setSecurityAnswer(null);
+ } else if (!updated.getSecurityQuestion().equals(original.getSecurityQuestion())
+ || StringUtils.isNotBlank(updated.getSecurityAnswer())) {
+
+ result.setSecurityQuestion(updated.getSecurityQuestion());
+ result.setSecurityAnswer(updated.getSecurityAnswer());
+ }
+
+ // 4. memberships
+ Map<Long, MembershipTO> updatedMembs = updated.getMembershipMap();
+ Map<Long, MembershipTO> originalMembs = original.getMembershipMap();
+
+ for (Map.Entry<Long, MembershipTO> entry : updatedMembs.entrySet()) {
+ MembershipMod membMod = new MembershipMod();
+ membMod.setRole(entry.getValue().getRoleId());
+
+ if (originalMembs.containsKey(entry.getKey())) {
+ // if memberships are actually same, just make the isEmpty() call below succeed
+ if (entry.getValue().equals(originalMembs.get(entry.getKey()))) {
+ membMod.setRole(0);
+ } else {
+ diff(entry.getValue(), originalMembs.get(entry.getKey()), membMod, false);
+ }
+ } else {
+ for (AttrTO attr : entry.getValue().getPlainAttrs()) {
+ AttrMod attrMod = new AttrMod();
+ attrMod.setSchema(attr.getSchema());
+ attrMod.getValuesToBeAdded().addAll(attr.getValues());
+
+ if (!attrMod.isEmpty()) {
+ membMod.getAttrsToUpdate().add(attrMod);
+ membMod.getAttrsToRemove().add(attrMod.getSchema());
+ }
+ }
+ for (AttrTO attr : entry.getValue().getDerAttrs()) {
+ membMod.getDerAttrsToAdd().add(attr.getSchema());
+ }
+ for (AttrTO attr : entry.getValue().getVirAttrs()) {
+ AttrMod attrMod = new AttrMod();
+ attrMod.setSchema(attr.getSchema());
+ attrMod.getValuesToBeAdded().addAll(attr.getValues());
+
+ if (!attrMod.isEmpty()) {
+ membMod.getVirAttrsToUpdate().add(attrMod);
+ membMod.getAttrsToRemove().add(attrMod.getSchema());
+ }
+ }
+ }
+
+ if (!membMod.isEmpty()) {
+ result.getMembershipsToAdd().add(membMod);
+ }
+ }
+
+ if (!incremental) {
+ Set<Long> originalRoles = new HashSet<>(originalMembs.keySet());
+ originalRoles.removeAll(updatedMembs.keySet());
+ for (Long roleId : originalRoles) {
+ result.getMembershipsToRemove().add(originalMembs.get(roleId).getKey());
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Calculate modifications needed by first in order to be equal to second.
+ *
+ * @param updated updated RoleTO
+ * @param original original RoleTO
+ * @return RoleMod containing differences
+ */
+ public static RoleMod diff(final RoleTO updated, final RoleTO original) {
+ return diff(updated, original, false);
+ }
+
+ /**
+ * Calculate modifications needed by first in order to be equal to second.
+ *
+ * @param updated updated RoleTO
+ * @param original original RoleTO
+ * @param incremental perform incremental diff (without removing existing info)
+ * @return RoleMod containing differences
+ */
+ public static RoleMod diff(final RoleTO updated, final RoleTO original, final boolean incremental) {
+ RoleMod result = new RoleMod();
+
+ diff(updated, original, result, incremental);
+
+ // 1. inheritance
+ result.setInheritOwner(updated.isInheritOwner());
+ result.setInheritTemplates(updated.isInheritTemplates());
+ result.setInheritAccountPolicy(updated.isInheritAccountPolicy());
+ result.setInheritPasswordPolicy(updated.isInheritPasswordPolicy());
+ result.setInheritPlainAttrs(updated.isInheritAttrs());
+ result.setInheritDerAttrs(updated.isInheritDerAttrs());
+ result.setInheritVirAttrs(updated.isInheritVirAttrs());
+
+ // 2. policies
+ result.setAccountPolicy(new ReferenceMod(updated.getAccountPolicy()));
+ result.setPasswordPolicy(new ReferenceMod(updated.getPasswordPolicy()));
+
+ // 3. name
+ if (!original.getName().equals(updated.getName())) {
+ result.setName(updated.getName());
+ }
+
+ // 4. entitlements
+ Set<String> updatedEnts = new HashSet<>(updated.getEntitlements());
+ Set<String> originalEnts = new HashSet<>(original.getEntitlements());
+ if (updatedEnts.equals(originalEnts)) {
+ result.setModEntitlements(false);
+ result.getEntitlements().clear();
+ } else {
+ result.setModEntitlements(true);
+ result.getEntitlements().addAll(updated.getEntitlements());
+ }
+
+ // 5. templates
+ Set<String> updatedTemplates = new HashSet<>(updated.getRAttrTemplates());
+ Set<String> originalTemplates = new HashSet<>(original.getRAttrTemplates());
+ if (updatedTemplates.equals(originalTemplates)) {
+ result.setModRAttrTemplates(false);
+ result.getRPlainAttrTemplates().clear();
+ } else {
+ result.setModRAttrTemplates(true);
+ result.getRPlainAttrTemplates().addAll(updated.getRAttrTemplates());
+ }
+ updatedTemplates = new HashSet<>(updated.getRDerAttrTemplates());
+ originalTemplates = new HashSet<>(original.getRDerAttrTemplates());
+ if (updatedTemplates.equals(originalTemplates)) {
+ result.setModRDerAttrTemplates(false);
+ result.getRDerAttrTemplates().clear();
+ } else {
+ result.setModRDerAttrTemplates(true);
+ result.getRDerAttrTemplates().addAll(updated.getRDerAttrTemplates());
+ }
+ updatedTemplates = new HashSet<>(updated.getRVirAttrTemplates());
+ originalTemplates = new HashSet<>(original.getRVirAttrTemplates());
+ if (updatedTemplates.equals(originalTemplates)) {
+ result.setModRVirAttrTemplates(false);
+ result.getRVirAttrTemplates().clear();
+ } else {
+ result.setModRVirAttrTemplates(true);
+ result.getRVirAttrTemplates().addAll(updated.getRVirAttrTemplates());
+ }
+ updatedTemplates = new HashSet<>(updated.getMAttrTemplates());
+ originalTemplates = new HashSet<>(original.getMAttrTemplates());
+ if (updatedTemplates.equals(originalTemplates)) {
+ result.setModMAttrTemplates(false);
+ result.getMPlainAttrTemplates().clear();
+ } else {
+ result.setModMAttrTemplates(true);
+ result.getMPlainAttrTemplates().addAll(updated.getMAttrTemplates());
+ }
+ updatedTemplates = new HashSet<>(updated.getMDerAttrTemplates());
+ originalTemplates = new HashSet<>(original.getMDerAttrTemplates());
+ if (updatedTemplates.equals(originalTemplates)) {
+ result.setModMDerAttrTemplates(false);
+ result.getMDerAttrTemplates().clear();
+ } else {
+ result.setModMDerAttrTemplates(true);
+ result.getMDerAttrTemplates().addAll(updated.getMDerAttrTemplates());
+ }
+ updatedTemplates = new HashSet<>(updated.getMVirAttrTemplates());
+ originalTemplates = new HashSet<>(original.getMVirAttrTemplates());
+ if (updatedTemplates.equals(originalTemplates)) {
+ result.setModMVirAttrTemplates(false);
+ result.getMVirAttrTemplates().clear();
+ } else {
+ result.setModMVirAttrTemplates(true);
+ result.getMVirAttrTemplates().addAll(updated.getMVirAttrTemplates());
+ }
+
+ // 6. owner
+ result.setUserOwner(new ReferenceMod(updated.getUserOwner()));
+ result.setRoleOwner(new ReferenceMod(updated.getRoleOwner()));
+
+ return result;
+ }
+
+ private static List<AttrTO> getUpdateValues(final Map<String, AttrTO> attrs,
+ final Set<String> attrsToBeRemoved, final Set<AttrMod> attrsToBeUpdated) {
+
+ Map<String, AttrTO> rwattrs = new HashMap<>(attrs);
+ for (String attrName : attrsToBeRemoved) {
+ rwattrs.remove(attrName);
+ }
+ for (AttrMod attrMod : attrsToBeUpdated) {
+ if (rwattrs.containsKey(attrMod.getSchema())) {
+ AttrTO attrTO = rwattrs.get(attrMod.getSchema());
+ attrTO.getValues().removeAll(attrMod.getValuesToBeRemoved());
+ attrTO.getValues().addAll(attrMod.getValuesToBeAdded());
+ } else {
+ AttrTO attrTO = new AttrTO();
+ attrTO.setSchema(attrMod.getSchema());
+ attrTO.getValues().addAll(attrMod.getValuesToBeAdded());
+
+ rwattrs.put(attrMod.getSchema(), attrTO);
+ }
+ }
+
+ return new ArrayList<>(rwattrs.values());
+ }
+
+ private static <T extends AbstractAttributableTO, K extends AbstractAttributableMod> void apply(final T to,
+ final K mod, final T result) {
+
+ // 1. attributes
+ result.getPlainAttrs().addAll(getUpdateValues(to.getAttrMap(),
+ mod.getAttrsToRemove(), mod.getAttrsToUpdate()));
+
+ // 2. derived attributes
+ Map<String, AttrTO> attrs = to.getDerAttrMap();
+ for (String attrName : mod.getDerAttrsToRemove()) {
+ attrs.remove(attrName);
+ }
+ for (String attrName : mod.getDerAttrsToAdd()) {
+ AttrTO attrTO = new AttrTO();
+ attrTO.setSchema(attrName);
+
+ attrs.put(attrName, attrTO);
+ }
+ result.getDerAttrs().addAll(attrs.values());
+
+ // 3. virtual attributes
+ result.getVirAttrs().addAll(getUpdateValues(to.getVirAttrMap(),
+ mod.getVirAttrsToRemove(), mod.getVirAttrsToUpdate()));
+
+ // 4. resources
+ if (result instanceof AbstractSubjectTO && mod instanceof AbstractSubjectMod) {
+ ((AbstractSubjectTO) result).getResources().removeAll(((AbstractSubjectMod) mod).getResourcesToRemove());
+ ((AbstractSubjectTO) result).getResources().addAll(((AbstractSubjectMod) mod).getResourcesToAdd());
+ }
+ }
+
+ public static UserTO apply(final UserTO userTO, final UserMod userMod) {
+ // 1. check same id
+ if (userTO.getKey() != userMod.getKey()) {
+ throw new IllegalArgumentException("UserTO and UserMod ids must be the same");
+ }
+
+ UserTO result = SerializationUtils.clone(userTO);
+ apply(userTO, userMod, result);
+
+ // 1. password
+ result.setPassword(userMod.getPassword());
+
+ // 2. username
+ if (userMod.getUsername() != null) {
+ result.setUsername(userMod.getUsername());
+ }
+ // 3. memberships
+ Map<Long, MembershipTO> membs = result.getMembershipMap();
+ for (Long membId : userMod.getMembershipsToRemove()) {
+ result.getMemberships().remove(membs.get(membId));
+ }
+ for (MembershipMod membMod : userMod.getMembershipsToAdd()) {
+ MembershipTO membTO = new MembershipTO();
+ membTO.setRoleId(membMod.getRole());
+
+ apply(membTO, membMod, membTO);
+ }
+
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientCompositeException.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientCompositeException.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientCompositeException.java
new file mode 100644
index 0000000..7322cc8
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientCompositeException.java
@@ -0,0 +1,96 @@
+/*
+ * 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.common.lib;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+
+public class SyncopeClientCompositeException extends SyncopeClientException {
+
+ private static final long serialVersionUID = 7882118041134372129L;
+
+ private final Set<SyncopeClientException> exceptions = new HashSet<>();
+
+ protected SyncopeClientCompositeException() {
+ super(ClientExceptionType.Composite);
+ }
+
+ public boolean hasExceptions() {
+ return !exceptions.isEmpty();
+ }
+
+ public boolean hasException(final ClientExceptionType exceptionType) {
+ return getException(exceptionType) != null;
+ }
+
+ public SyncopeClientException getException(final ClientExceptionType exceptionType) {
+ boolean found = false;
+ SyncopeClientException syncopeClientException = null;
+ for (Iterator<SyncopeClientException> itor = exceptions.iterator(); itor.hasNext() && !found;) {
+ syncopeClientException = itor.next();
+ if (syncopeClientException.getType().equals(exceptionType)) {
+ found = true;
+ }
+ }
+
+ return found
+ ? syncopeClientException
+ : null;
+ }
+
+ public Set<SyncopeClientException> getExceptions() {
+ return exceptions;
+ }
+
+ public boolean addException(final SyncopeClientException exception) {
+ if (exception.getType() == null) {
+ throw new IllegalArgumentException(exception + " does not have the right "
+ + ClientExceptionType.class.getName() + " set");
+ }
+
+ return exceptions.add(exception);
+ }
+
+ @Override
+ public String getMessage() {
+ StringBuilder message = new StringBuilder();
+
+ message.append("{");
+ Iterator<SyncopeClientException> iter = getExceptions().iterator();
+ while (iter.hasNext()) {
+ SyncopeClientException e = iter.next();
+ message.append("[");
+ message.append(e.getMessage());
+ message.append("]");
+ if (iter.hasNext()) {
+ message.append(", ");
+ }
+ }
+ message.append("}");
+
+ return message.toString();
+ }
+
+ @Override
+ public String getLocalizedMessage() {
+ return getMessage();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientException.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientException.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientException.java
new file mode 100644
index 0000000..2243835
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/SyncopeClientException.java
@@ -0,0 +1,97 @@
+/*
+ * 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.common.lib;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+
+public class SyncopeClientException extends RuntimeException {
+
+ private static final long serialVersionUID = 3380920886511913475L;
+
+ private ClientExceptionType type;
+
+ private final List<String> elements = new ArrayList<>();
+
+ public static SyncopeClientException build(final ClientExceptionType type) {
+ if (type == ClientExceptionType.Composite) {
+ throw new IllegalArgumentException("Composite exceptions must be obtained via buildComposite()");
+ }
+ return new SyncopeClientException(type);
+ }
+
+ public static SyncopeClientCompositeException buildComposite() {
+ return new SyncopeClientCompositeException();
+ }
+
+ protected SyncopeClientException(final ClientExceptionType type) {
+ super();
+ setType(type);
+ }
+
+ public boolean isComposite() {
+ return getType() == ClientExceptionType.Composite;
+ }
+
+ public SyncopeClientCompositeException asComposite() {
+ if (!isComposite()) {
+ throw new IllegalArgumentException("This is not a composite exception");
+ }
+
+ return (SyncopeClientCompositeException) this;
+ }
+
+ public ClientExceptionType getType() {
+ return type;
+ }
+
+ public final void setType(final ClientExceptionType type) {
+ this.type = type;
+ }
+
+ public List<String> getElements() {
+ return elements;
+ }
+
+ public boolean isEmpty() {
+ return elements.isEmpty();
+ }
+
+ public int size() {
+ return elements.size();
+ }
+
+ @Override
+ public String getMessage() {
+ StringBuilder message = new StringBuilder();
+
+ message.append(getType());
+ message.append(" ");
+ message.append(getElements());
+
+ return message.toString();
+ }
+
+ @Override
+ public String getLocalizedMessage() {
+ return getMessage();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
index 7339565..5d6b982 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/AbstractAttributableMod.java
@@ -38,9 +38,9 @@ public abstract class AbstractAttributableMod extends AbstractBaseBean {
protected long key;
- protected final Set<AttrMod> attrsToUpdate = new HashSet<>();
+ protected final Set<AttrMod> plainAttrsToUpdate = new HashSet<>();
- protected final Set<String> attrsToRemove = new HashSet<>();
+ protected final Set<String> plainAttrsToRemove = new HashSet<>();
protected final Set<String> derAttrsToAdd = new HashSet<>();
@@ -58,18 +58,18 @@ public abstract class AbstractAttributableMod extends AbstractBaseBean {
this.key = key;
}
- @XmlElementWrapper(name = "attributesToRemove")
+ @XmlElementWrapper(name = "plainAttrsToRemove")
@XmlElement(name = "attribute")
- @JsonProperty("attributesToRemove")
+ @JsonProperty("plainAttrsToRemove")
public Set<String> getAttrsToRemove() {
- return attrsToRemove;
+ return plainAttrsToRemove;
}
- @XmlElementWrapper(name = "attributesToUpdate")
+ @XmlElementWrapper(name = "plainAttrsToUpdate")
@XmlElement(name = "attributeMod")
- @JsonProperty("attributesToUpdate")
+ @JsonProperty("plainAttrsToUpdate")
public Set<AttrMod> getAttrsToUpdate() {
- return attrsToUpdate;
+ return plainAttrsToUpdate;
}
@XmlElementWrapper(name = "derAttrsToAdd")
@@ -104,7 +104,7 @@ public abstract class AbstractAttributableMod extends AbstractBaseBean {
* @return true is all backing Sets are empty.
*/
public boolean isEmpty() {
- return attrsToUpdate.isEmpty() && attrsToRemove.isEmpty()
+ return plainAttrsToUpdate.isEmpty() && plainAttrsToRemove.isEmpty()
&& derAttrsToAdd.isEmpty() && derAttrsToRemove.isEmpty()
&& virAttrsToUpdate.isEmpty() && virAttrsToRemove.isEmpty();
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java
new file mode 100644
index 0000000..bdcfcbf
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/MembershipMod.java
@@ -0,0 +1,46 @@
+/*
+ * 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.common.lib.mod;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement
+@XmlType
+public class MembershipMod extends AbstractAttributableMod {
+
+ private static final long serialVersionUID = 2511869129977331525L;
+
+ private long role;
+
+ public long getRole() {
+ return role;
+ }
+
+ public void setRole(final long role) {
+ this.role = role;
+ }
+
+ @JsonIgnore
+ @Override
+ public boolean isEmpty() {
+ return super.isEmpty() && role == 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ReferenceMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ReferenceMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ReferenceMod.java
new file mode 100644
index 0000000..e8356c2
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ReferenceMod.java
@@ -0,0 +1,53 @@
+/*
+ * 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.common.lib.mod;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+/**
+ * This class is used to specify the willing to modify an external reference id. Use 'null' ReferenceMod to keep the
+ * current reference id; use a ReferenceMod with a null id to try to reset the reference id; use a ReferenceMod with a
+ * not null id to specify a new reference id.
+ */
+@XmlRootElement(name = "referenceMod")
+@XmlType
+public class ReferenceMod extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -4188817853738067677L;
+
+ private Long key;
+
+ public ReferenceMod() {
+ this.key = null;
+ }
+
+ public ReferenceMod(final Long key) {
+ this.key = key;
+ }
+
+ public Long getKey() {
+ return key;
+ }
+
+ public void setKey(final Long key) {
+ this.key = key;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ResourceAssociationMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ResourceAssociationMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ResourceAssociationMod.java
new file mode 100644
index 0000000..6312349
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/ResourceAssociationMod.java
@@ -0,0 +1,80 @@
+/*
+ * 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.common.lib.mod;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.common.lib.wrap.ResourceName;
+
+/**
+ * This class is used to specify the willing to create associations between user and external references.
+ * Password can be provided if required by an assign or provisioning operation.
+ *
+ * @see org.apache.syncope.common.types.ResourceAssociationActionType
+ */
+@XmlRootElement(name = "resourceAssociationMod")
+@XmlType
+public class ResourceAssociationMod extends AbstractBaseBean {
+
+ private static final long serialVersionUID = -4188817853738067678L;
+
+ /**
+ * Target external resources.
+ */
+ private final List<ResourceName> targetResources = new ArrayList<ResourceName>();
+
+ /**
+ * Indicate the willing to change password on target external resources.
+ */
+ private boolean changePwd;
+
+ /**
+ * Indicate the new password to be provisioned on target external resources.
+ */
+ private String password;
+
+ @XmlElementWrapper(name = "resources")
+ @XmlElement(name = "resource")
+ @JsonProperty("resources")
+ public List<ResourceName> getTargetResources() {
+ return targetResources;
+ }
+
+ public boolean isChangePwd() {
+ return changePwd;
+ }
+
+ public void setChangePwd(boolean changePwd) {
+ this.changePwd = changePwd;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/RoleMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/RoleMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/RoleMod.java
new file mode 100644
index 0000000..b1b8f4f
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/RoleMod.java
@@ -0,0 +1,300 @@
+/*
+ * 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.common.lib.mod;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "roleMod")
+@XmlType
+public class RoleMod extends AbstractSubjectMod {
+
+ private static final long serialVersionUID = 7455805264680210747L;
+
+ private String name;
+
+ private ReferenceMod userOwner;
+
+ private ReferenceMod roleOwner;
+
+ private Boolean inheritOwner;
+
+ private Boolean inheritTemplates;
+
+ private Boolean inheritPlainAttrs;
+
+ private Boolean inheritDerAttrs;
+
+ private Boolean inheritVirAttrs;
+
+ private Boolean inheritAccountPolicy;
+
+ private Boolean inheritPasswordPolicy;
+
+ private boolean modEntitlements;
+
+ private final List<String> entitlements = new ArrayList<>();
+
+ private boolean modRAttrTemplates;
+
+ private final List<String> rPlainAttrTemplates = new ArrayList<>();
+
+ private boolean modRDerAttrTemplates;
+
+ private final List<String> rDerAttrTemplates = new ArrayList<>();
+
+ private boolean modRVirAttrTemplates;
+
+ private final List<String> rVirAttrTemplates = new ArrayList<>();
+
+ private boolean modMAttrTemplates;
+
+ private final List<String> mPlainAttrTemplates = new ArrayList<>();
+
+ private boolean modMDerAttrTemplates;
+
+ private final List<String> mDerAttrTemplates = new ArrayList<>();
+
+ private boolean modMVirAttrTemplates;
+
+ private final List<String> mVirAttrTemplates = new ArrayList<>();
+
+ private ReferenceMod passwordPolicy;
+
+ private ReferenceMod accountPolicy;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public ReferenceMod getUserOwner() {
+ return userOwner;
+ }
+
+ public void setUserOwner(final ReferenceMod userOwner) {
+ this.userOwner = userOwner;
+ }
+
+ public ReferenceMod getRoleOwner() {
+ return roleOwner;
+ }
+
+ public void setRoleOwner(final ReferenceMod roleOwner) {
+ this.roleOwner = roleOwner;
+ }
+
+ public Boolean getInheritOwner() {
+ return inheritOwner;
+ }
+
+ public void setInheritOwner(final Boolean inheritOwner) {
+ this.inheritOwner = inheritOwner;
+ }
+
+ public Boolean getInheritTemplates() {
+ return inheritTemplates;
+ }
+
+ public void setInheritTemplates(final Boolean inheritTemplates) {
+ this.inheritTemplates = inheritTemplates;
+ }
+
+ public Boolean getInheritPlainAttrs() {
+ return inheritPlainAttrs;
+ }
+
+ public void setInheritPlainAttrs(final Boolean inheritAttrs) {
+ this.inheritPlainAttrs = inheritAttrs;
+ }
+
+ public Boolean getInheritDerAttrs() {
+ return inheritDerAttrs;
+ }
+
+ public void setInheritDerAttrs(final Boolean inheritDerAttrs) {
+ this.inheritDerAttrs = inheritDerAttrs;
+ }
+
+ public Boolean getInheritVirAttrs() {
+ return inheritVirAttrs;
+ }
+
+ public void setInheritVirAttrs(final Boolean inheritVirAttrs) {
+ this.inheritVirAttrs = inheritVirAttrs;
+ }
+
+ public boolean isModEntitlements() {
+ return modEntitlements;
+ }
+
+ public void setModEntitlements(final boolean modEntitlements) {
+ this.modEntitlements = modEntitlements;
+ }
+
+ @XmlElementWrapper(name = "entitlements")
+ @XmlElement(name = "entitlement")
+ @JsonProperty("entitlements")
+ public List<String> getEntitlements() {
+ return entitlements;
+ }
+
+ public boolean isModRAttrTemplates() {
+ return modRAttrTemplates;
+ }
+
+ public void setModRAttrTemplates(final boolean modRAttrTemplates) {
+ this.modRAttrTemplates = modRAttrTemplates;
+ }
+
+ @XmlElementWrapper(name = "rPlainAttrTemplates")
+ @XmlElement(name = "rAttrTemplate")
+ @JsonProperty("rPlainAttrTemplates")
+ public List<String> getRPlainAttrTemplates() {
+ return rPlainAttrTemplates;
+ }
+
+ public boolean isModRDerAttrTemplates() {
+ return modRDerAttrTemplates;
+ }
+
+ public void setModRDerAttrTemplates(final boolean modRDerAttrTemplates) {
+ this.modRDerAttrTemplates = modRDerAttrTemplates;
+ }
+
+ @XmlElementWrapper(name = "rDerAttrTemplates")
+ @XmlElement(name = "rDerAttrTemplate")
+ @JsonProperty("rDerAttrTemplates")
+ public List<String> getRDerAttrTemplates() {
+ return rDerAttrTemplates;
+ }
+
+ public boolean isModRVirAttrTemplates() {
+ return modRVirAttrTemplates;
+ }
+
+ public void setModRVirAttrTemplates(final boolean modRVirAttrTemplates) {
+ this.modRVirAttrTemplates = modRVirAttrTemplates;
+ }
+
+ @XmlElementWrapper(name = "rVirAttrTemplates")
+ @XmlElement(name = "rVirAttrTemplate")
+ @JsonProperty("rVirAttrTemplates")
+ public List<String> getRVirAttrTemplates() {
+ return rVirAttrTemplates;
+ }
+
+ public boolean isModMAttrTemplates() {
+ return modMAttrTemplates;
+ }
+
+ public void setModMAttrTemplates(final boolean modMAttrTemplates) {
+ this.modMAttrTemplates = modMAttrTemplates;
+ }
+
+ @XmlElementWrapper(name = "mPlainAttrTemplates")
+ @XmlElement(name = "mAttrTemplate")
+ @JsonProperty("mPlainAttrTemplates")
+ public List<String> getMPlainAttrTemplates() {
+ return mPlainAttrTemplates;
+ }
+
+ public boolean isModMDerAttrTemplates() {
+ return modMDerAttrTemplates;
+ }
+
+ public void setModMDerAttrTemplates(final boolean modMDerAttrTemplates) {
+ this.modMDerAttrTemplates = modMDerAttrTemplates;
+ }
+
+ @XmlElementWrapper(name = "mDerAttrTemplates")
+ @XmlElement(name = "mDerAttrTemplate")
+ @JsonProperty("mDerAttrTemplates")
+ public List<String> getMDerAttrTemplates() {
+ return mDerAttrTemplates;
+ }
+
+ public boolean isModMVirAttrTemplates() {
+ return modMVirAttrTemplates;
+ }
+
+ public void setModMVirAttrTemplates(final boolean modMVirAttrTemplates) {
+ this.modMVirAttrTemplates = modMVirAttrTemplates;
+ }
+
+ @XmlElementWrapper(name = "mVirAttrTemplates")
+ @XmlElement(name = "mVirAttrTemplate")
+ @JsonProperty("mVirAttrTemplates")
+ public List<String> getMVirAttrTemplates() {
+ return mVirAttrTemplates;
+ }
+
+ public ReferenceMod getPasswordPolicy() {
+ return passwordPolicy;
+ }
+
+ public void setPasswordPolicy(final ReferenceMod passwordPolicy) {
+ this.passwordPolicy = passwordPolicy;
+ }
+
+ public Boolean getInheritPasswordPolicy() {
+ return inheritPasswordPolicy;
+ }
+
+ public void setInheritPasswordPolicy(final Boolean inheritPasswordPolicy) {
+ this.inheritPasswordPolicy = inheritPasswordPolicy;
+ }
+
+ public ReferenceMod getAccountPolicy() {
+ return accountPolicy;
+ }
+
+ public void setAccountPolicy(final ReferenceMod accountPolicy) {
+ this.accountPolicy = accountPolicy;
+ }
+
+ public Boolean getInheritAccountPolicy() {
+ return inheritAccountPolicy;
+ }
+
+ public void setInheritAccountPolicy(final Boolean inheritAccountPolicy) {
+ this.inheritAccountPolicy = inheritAccountPolicy;
+ }
+
+ @JsonIgnore
+ @Override
+ public boolean isEmpty() {
+ return super.isEmpty() && name == null && userOwner == null && roleOwner == null
+ && inheritTemplates == null && inheritOwner == null
+ && inheritAccountPolicy == null && inheritPasswordPolicy == null
+ && inheritPlainAttrs == null && inheritDerAttrs == null && inheritVirAttrs == null
+ && accountPolicy == null && passwordPolicy == null && entitlements.isEmpty()
+ && rPlainAttrTemplates.isEmpty() && rDerAttrTemplates.isEmpty() && rVirAttrTemplates.isEmpty()
+ && mPlainAttrTemplates.isEmpty() && mDerAttrTemplates.isEmpty() && mVirAttrTemplates.isEmpty();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java
new file mode 100644
index 0000000..3ddf263
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java
@@ -0,0 +1,108 @@
+/*
+ * 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.common.lib.mod;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+
+@XmlRootElement(name = "statusMod")
+@XmlType
+public class StatusMod extends AbstractBaseBean {
+
+ private static final long serialVersionUID = 3230910033784302656L;
+
+ @XmlEnum
+ @XmlType(name = "statusModType")
+ public enum ModType {
+
+ ACTIVATE,
+ SUSPEND,
+ REACTIVATE;
+
+ }
+
+ /**
+ * Id of user to for which status update is requested.
+ */
+ private long id;
+
+ private ModType type;
+
+ /**
+ * Update token (if required).
+ */
+ private String token;
+
+ /**
+ * Whether update should be performed on internal storage.
+ */
+ private boolean onSyncope = true;
+
+ /**
+ * External resources for which update is needed to be propagated.
+ */
+ private final List<String> resourceNames = new ArrayList<>();
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public ModType getType() {
+ return type;
+ }
+
+ public void setType(final ModType type) {
+ this.type = type;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(final String token) {
+ this.token = token;
+ }
+
+ public boolean isOnSyncope() {
+ return onSyncope;
+ }
+
+ public void setOnSyncope(final boolean onSyncope) {
+ this.onSyncope = onSyncope;
+ }
+
+ @XmlElementWrapper(name = "resources")
+ @XmlElement(name = "resource")
+ @JsonProperty("resources")
+ public List<String> getResourceNames() {
+ return resourceNames;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java
new file mode 100644
index 0000000..0f421be
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/UserMod.java
@@ -0,0 +1,123 @@
+/*
+ * 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.common.lib.mod;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.HashSet;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "userMod")
+@XmlType
+public class UserMod extends AbstractSubjectMod {
+
+ private static final long serialVersionUID = 3081848906558106204L;
+
+ private String password;
+
+ private String username;
+
+ private final Set<MembershipMod> membershipsToAdd;
+
+ private final Set<Long> membershipsToRemove;
+
+ private StatusMod pwdPropRequest;
+
+ private Long securityQuestion;
+
+ private String securityAnswer;
+
+ public UserMod() {
+ super();
+
+ membershipsToAdd = new HashSet<>();
+ membershipsToRemove = new HashSet<>();
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(final String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(final String password) {
+ this.password = password;
+ }
+
+ @XmlElementWrapper(name = "membershipsToAdd")
+ @XmlElement(name = "membership")
+ @JsonProperty("membershipsToAdd")
+ public Set<MembershipMod> getMembershipsToAdd() {
+ return membershipsToAdd;
+ }
+
+ @XmlElementWrapper(name = "membershipsToRemove")
+ @XmlElement(name = "membership")
+ @JsonProperty("membershipsToRemove")
+ public Set<Long> getMembershipsToRemove() {
+ return membershipsToRemove;
+ }
+
+ public StatusMod getPwdPropRequest() {
+ return pwdPropRequest;
+ }
+
+ public void setPwdPropRequest(final StatusMod pwdPropRequest) {
+ this.pwdPropRequest = pwdPropRequest;
+ }
+
+ public Long getSecurityQuestion() {
+ return securityQuestion;
+ }
+
+ public void setSecurityQuestion(final Long securityQuestion) {
+ this.securityQuestion = securityQuestion;
+ }
+
+ public String getSecurityAnswer() {
+ return securityAnswer;
+ }
+
+ public void setSecurityAnswer(final String securityAnswer) {
+ this.securityAnswer = securityAnswer;
+ }
+
+ @JsonIgnore
+ @Override
+ public boolean isEmpty() {
+ return super.isEmpty()
+ && password == null
+ && username == null
+ && membershipsToAdd.isEmpty()
+ && membershipsToRemove.isEmpty()
+ && pwdPropRequest == null
+ && securityQuestion == null
+ && securityAnswer == null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/package-info.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/package-info.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/package-info.java
new file mode 100644
index 0000000..866b275
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/mod/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@XmlSchema(namespace = SyncopeConstants.NAMESPACE)
+package org.apache.syncope.common.lib.mod;
+
+import javax.xml.bind.annotation.XmlSchema;
+import org.apache.syncope.common.lib.SyncopeConstants;
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/RoleReportletConf.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/RoleReportletConf.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/RoleReportletConf.java
index 55e2da9..295316b 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/RoleReportletConf.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/RoleReportletConf.java
@@ -39,7 +39,7 @@ public class RoleReportletConf extends AbstractReportletConf {
@XmlType(name = "roleReportletConfFeature")
public enum Feature {
- id,
+ key,
name,
roleOwner,
userOwner,
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
index 2c6ed17..afd806a 100644
--- a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/report/UserReportletConf.java
@@ -38,7 +38,7 @@ public class UserReportletConf extends AbstractReportletConf {
@XmlType(name = "userReportletConfFeature")
public enum Feature {
- id,
+ key,
username,
workflowId,
status,
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/OrderByClauseBuilder.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/OrderByClauseBuilder.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/OrderByClauseBuilder.java
new file mode 100644
index 0000000..41d152c
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/OrderByClauseBuilder.java
@@ -0,0 +1,45 @@
+/*
+ * 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.common.lib.search;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Simple builder for generating <tt>orderby</tt> values.
+ */
+public class OrderByClauseBuilder {
+
+ private final StringBuilder builder = new StringBuilder();
+
+ public OrderByClauseBuilder asc(final String key) {
+ builder.append(key).append(" ASC,");
+ return this;
+ }
+
+ public OrderByClauseBuilder desc(final String key) {
+ builder.append(key).append(" DESC,");
+ return this;
+ }
+
+ public String build() {
+ return builder.length() == 0
+ ? StringUtils.EMPTY
+ : builder.deleteCharAt(builder.length() - 1).toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleFiqlSearchConditionBuilder.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleFiqlSearchConditionBuilder.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleFiqlSearchConditionBuilder.java
new file mode 100644
index 0000000..b6cbb6d
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleFiqlSearchConditionBuilder.java
@@ -0,0 +1,90 @@
+/*
+ * 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.common.lib.search;
+
+import java.util.Map;
+import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
+import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser;
+
+/**
+ * Extends <tt>SyncopeFiqlSearchConditionBuilder</tt> by providing some additional facilities for searching
+ * roles in Syncope.
+ */
+public class RoleFiqlSearchConditionBuilder extends SyncopeFiqlSearchConditionBuilder {
+
+ public RoleFiqlSearchConditionBuilder() {
+ super();
+ }
+
+ public RoleFiqlSearchConditionBuilder(final Map<String, String> properties) {
+ super(properties);
+ }
+
+ @Override
+ protected Builder newBuilderInstance() {
+ return new Builder(properties);
+ }
+
+ @Override
+ public RoleProperty is(final String property) {
+ return newBuilderInstance().is(property);
+ }
+
+ public CompleteCondition hasEntitlements(final String entitlement, final String... moreEntitlements) {
+ return newBuilderInstance().is(SpecialAttr.ENTITLEMENTS.toString()).
+ hasEntitlements(entitlement, moreEntitlements);
+ }
+
+ public CompleteCondition hasNotEntitlements(final String entitlement, final String... moreEntitlements) {
+ return newBuilderInstance().is(SpecialAttr.ENTITLEMENTS.toString()).
+ hasNotEntitlements(entitlement, moreEntitlements);
+ }
+
+ protected static class Builder extends SyncopeFiqlSearchConditionBuilder.Builder
+ implements RoleProperty, CompleteCondition {
+
+ public Builder(final Map<String, String> properties) {
+ super(properties);
+ }
+
+ public Builder(final Builder parent) {
+ super(parent);
+ }
+
+ @Override
+ public RoleProperty is(final String property) {
+ Builder b = new Builder(this);
+ b.result = property;
+ return b;
+ }
+
+ @Override
+ public CompleteCondition hasEntitlements(final String entitlement, final String... moreEntitlements) {
+ this.result = SpecialAttr.ENTITLEMENTS.toString();
+ return condition(FiqlParser.EQ, entitlement, (Object[]) moreEntitlements);
+ }
+
+ @Override
+ public CompleteCondition hasNotEntitlements(final String entitlement, final String... moreEntitlements) {
+ this.result = SpecialAttr.ENTITLEMENTS.toString();
+ return condition(FiqlParser.NEQ, entitlement, (Object[]) moreEntitlements);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleProperty.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleProperty.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleProperty.java
new file mode 100644
index 0000000..433ed11
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/search/RoleProperty.java
@@ -0,0 +1,29 @@
+/*
+ * 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.common.lib.search;
+
+import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
+
+public interface RoleProperty extends SyncopeProperty {
+
+ CompleteCondition hasEntitlements(String entitlement, String... moreEntitlements);
+
+ CompleteCondition hasNotEntitlements(String entitlement, String... moreEntitlements);
+
+}
[09/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/PolicyController.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/PolicyController.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/PolicyController.java
new file mode 100644
index 0000000..fbfb127
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/PolicyController.java
@@ -0,0 +1,197 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.to.AbstractPolicyTO;
+import org.apache.syncope.common.lib.to.AccountPolicyTO;
+import org.apache.syncope.common.lib.to.PasswordPolicyTO;
+import org.apache.syncope.common.lib.to.SyncPolicyTO;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.PolicyDAO;
+import org.apache.syncope.persistence.api.entity.AccountPolicy;
+import org.apache.syncope.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.persistence.api.entity.Policy;
+import org.apache.syncope.persistence.api.entity.SyncPolicy;
+import org.apache.syncope.server.logic.data.PolicyDataBinder;
+import org.apache.syncope.server.logic.init.ImplementationClassNamesLoader;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PolicyController extends AbstractTransactionalLogic<AbstractPolicyTO> {
+
+ @Autowired
+ private ImplementationClassNamesLoader classNamesLoader;
+
+ @Autowired
+ private PolicyDAO policyDAO;
+
+ @Autowired
+ private PolicyDataBinder binder;
+
+ @PreAuthorize("hasRole('POLICY_CREATE')")
+ public <T extends AbstractPolicyTO> T create(final T policyTO) {
+ return binder.getPolicyTO(policyDAO.save(binder.getPolicy(null, policyTO)));
+ }
+
+ private <T extends AbstractPolicyTO, K extends Policy> T update(final T policyTO, final K policy) {
+ binder.getPolicy(policy, policyTO);
+ K savedPolicy = policyDAO.save(policy);
+ return binder.getPolicyTO(savedPolicy);
+ }
+
+ @PreAuthorize("hasRole('POLICY_UPDATE')")
+ public PasswordPolicyTO update(final PasswordPolicyTO policyTO) {
+ Policy policy = policyDAO.find(policyTO.getId());
+ if (!(policy instanceof PasswordPolicy)) {
+ throw new NotFoundException("PasswordPolicy with id " + policyTO.getId());
+ }
+
+ return update(policyTO, policy);
+ }
+
+ @PreAuthorize("hasRole('POLICY_UPDATE')")
+ public AccountPolicyTO update(final AccountPolicyTO policyTO) {
+ Policy policy = policyDAO.find(policyTO.getId());
+ if (!(policy instanceof AccountPolicy)) {
+ throw new NotFoundException("AccountPolicy with id " + policyTO.getId());
+ }
+
+ return update(policyTO, policy);
+ }
+
+ @PreAuthorize("hasRole('POLICY_UPDATE')")
+ public SyncPolicyTO update(final SyncPolicyTO policyTO) {
+ Policy policy = policyDAO.find(policyTO.getId());
+ if (!(policy instanceof SyncPolicy)) {
+ throw new NotFoundException("SyncPolicy with id " + policyTO.getId());
+ }
+
+ return update(policyTO, policy);
+ }
+
+ @PreAuthorize("hasRole('POLICY_LIST')")
+ @SuppressWarnings("unchecked")
+ public <T extends AbstractPolicyTO> List<T> list(final PolicyType type) {
+
+ List<? extends Policy> policies = policyDAO.find(type);
+
+ final List<T> policyTOs = new ArrayList<T>();
+ for (Policy policy : policies) {
+ policyTOs.add((T) binder.getPolicyTO(policy));
+ }
+
+ return policyTOs;
+ }
+
+ @PreAuthorize("hasRole('POLICY_READ')")
+ public PasswordPolicyTO getGlobalPasswordPolicy() {
+ PasswordPolicy policy = policyDAO.getGlobalPasswordPolicy();
+ if (policy == null) {
+ throw new NotFoundException("No password policy found");
+ }
+
+ return (PasswordPolicyTO) binder.getPolicyTO(policy);
+ }
+
+ @PreAuthorize("hasRole('POLICY_READ')")
+ public AccountPolicyTO getGlobalAccountPolicy() {
+ AccountPolicy policy = policyDAO.getGlobalAccountPolicy();
+ if (policy == null) {
+ throw new NotFoundException("No account policy found");
+ }
+
+ return (AccountPolicyTO) binder.getPolicyTO(policy);
+ }
+
+ @PreAuthorize("hasRole('POLICY_READ')")
+ public SyncPolicyTO getGlobalSyncPolicy() {
+ SyncPolicy policy = policyDAO.getGlobalSyncPolicy();
+ if (policy == null) {
+ throw new NotFoundException("No sync policy found");
+ }
+
+ return (SyncPolicyTO) binder.getPolicyTO(policy);
+ }
+
+ @PreAuthorize("hasRole('POLICY_READ')")
+ public <T extends AbstractPolicyTO> T read(final Long id) {
+ Policy policy = policyDAO.find(id);
+ if (policy == null) {
+ throw new NotFoundException("Policy " + id + " not found");
+ }
+
+ return binder.getPolicyTO(policy);
+ }
+
+ @PreAuthorize("hasRole('POLICY_DELETE')")
+ public <T extends AbstractPolicyTO> T delete(final Long id) {
+ Policy policy = policyDAO.find(id);
+ if (policy == null) {
+ throw new NotFoundException("Policy " + id + " not found");
+ }
+
+ T policyToDelete = binder.getPolicyTO(policy);
+ policyDAO.delete(policy);
+
+ return policyToDelete;
+ }
+
+ @PreAuthorize("hasRole('POLICY_LIST')")
+ public Set<String> getSyncCorrelationRuleClasses() {
+ return classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.SYNC_CORRELATION_RULES);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected AbstractPolicyTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+ Long id = null;
+
+ if (ArrayUtils.isNotEmpty(args)) {
+ for (int i = 0; id == null && i < args.length; i++) {
+ if (args[i] instanceof Long) {
+ id = (Long) args[i];
+ } else if (args[i] instanceof AbstractPolicyTO) {
+ id = ((AbstractPolicyTO) args[i]).getId();
+ }
+ }
+ }
+
+ if ((id != null) && !id.equals(0l)) {
+ try {
+ return binder.getPolicyTO(policyDAO.find(id));
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ReportLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ReportLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ReportLogic.java
new file mode 100644
index 0000000..0d8af57
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ReportLogic.java
@@ -0,0 +1,348 @@
+/*
+ * 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.server.logic;
+
+import java.io.ByteArrayInputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.zip.ZipInputStream;
+import org.apache.cocoon.optional.pipeline.components.sax.fop.FopSerializer;
+import org.apache.cocoon.pipeline.NonCachingPipeline;
+import org.apache.cocoon.pipeline.Pipeline;
+import org.apache.cocoon.sax.SAXPipelineComponent;
+import org.apache.cocoon.sax.component.XMLGenerator;
+import org.apache.cocoon.sax.component.XMLSerializer;
+import org.apache.cocoon.sax.component.XSLTTransformer;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.report.ReportletConf;
+import org.apache.syncope.common.lib.to.ReportExecTO;
+import org.apache.syncope.common.lib.to.ReportTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ReportExecExportFormat;
+import org.apache.syncope.common.lib.types.ReportExecStatus;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.ReportDAO;
+import org.apache.syncope.persistence.api.dao.ReportExecDAO;
+import org.apache.syncope.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.Report;
+import org.apache.syncope.persistence.api.entity.ReportExec;
+import org.apache.syncope.server.logic.data.ReportDataBinder;
+import org.apache.syncope.server.logic.init.JobInstanceLoader;
+import org.apache.syncope.server.logic.report.Reportlet;
+import org.apache.syncope.server.logic.report.TextSerializer;
+import org.apache.xmlgraphics.util.MimeConstants;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class ReportLogic extends AbstractTransactionalLogic<ReportTO> {
+
+ @Autowired
+ private ReportDAO reportDAO;
+
+ @Autowired
+ private ReportExecDAO reportExecDAO;
+
+ @Autowired
+ private JobInstanceLoader jobInstanceLoader;
+
+ @Autowired
+ private SchedulerFactoryBean scheduler;
+
+ @Autowired
+ private ReportDataBinder binder;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ @PreAuthorize("hasRole('REPORT_CREATE')")
+ public ReportTO create(final ReportTO reportTO) {
+ Report report = entityFactory.newEntity(Report.class);
+ binder.getReport(report, reportTO);
+ report = reportDAO.save(report);
+
+ try {
+ jobInstanceLoader.registerJob(report);
+ } catch (Exception e) {
+ LOG.error("While registering quartz job for report " + report.getKey(), e);
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Scheduling);
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
+
+ return binder.getReportTO(report);
+ }
+
+ @PreAuthorize("hasRole('REPORT_UPDATE')")
+ public ReportTO update(final ReportTO reportTO) {
+ Report report = reportDAO.find(reportTO.getId());
+ if (report == null) {
+ throw new NotFoundException("Report " + reportTO.getId());
+ }
+
+ binder.getReport(report, reportTO);
+ report = reportDAO.save(report);
+
+ try {
+ jobInstanceLoader.registerJob(report);
+ } catch (Exception e) {
+ LOG.error("While registering quartz job for report " + report.getKey(), e);
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Scheduling);
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
+
+ return binder.getReportTO(report);
+ }
+
+ @PreAuthorize("hasRole('REPORT_LIST')")
+ public int count() {
+ return reportDAO.count();
+ }
+
+ @PreAuthorize("hasRole('REPORT_LIST')")
+ public List<ReportTO> list(final int page, final int size, final List<OrderByClause> orderByClauses) {
+ List<Report> reports = reportDAO.findAll(page, size, orderByClauses);
+ List<ReportTO> result = new ArrayList<ReportTO>(reports.size());
+ for (Report report : reports) {
+ result.add(binder.getReportTO(report));
+ }
+ return result;
+ }
+
+ @PreAuthorize("hasRole('REPORT_LIST')")
+ @SuppressWarnings("rawtypes")
+ public Set<String> getReportletConfClasses() {
+ Set<String> reportletConfClasses = new HashSet<String>();
+
+ for (Class<Reportlet> reportletClass : binder.getAllReportletClasses()) {
+ Class<? extends ReportletConf> reportletConfClass = binder.getReportletConfClass(reportletClass);
+ if (reportletConfClass != null) {
+ reportletConfClasses.add(reportletConfClass.getName());
+ }
+ }
+
+ return reportletConfClasses;
+ }
+
+ @PreAuthorize("hasRole('REPORT_READ')")
+ public ReportTO read(final Long reportId) {
+ Report report = reportDAO.find(reportId);
+ if (report == null) {
+ throw new NotFoundException("Report " + reportId);
+ }
+ return binder.getReportTO(report);
+ }
+
+ @PreAuthorize("hasRole('REPORT_READ')")
+ @Transactional(readOnly = true)
+ public ReportExecTO readExecution(final Long executionId) {
+ ReportExec reportExec = reportExecDAO.find(executionId);
+ if (reportExec == null) {
+ throw new NotFoundException("Report execution " + executionId);
+ }
+ return binder.getReportExecTO(reportExec);
+ }
+
+ @PreAuthorize("hasRole('REPORT_READ')")
+ public void exportExecutionResult(final OutputStream os, final ReportExec reportExec,
+ final ReportExecExportFormat format) {
+
+ // streaming SAX handler from a compressed byte array stream
+ ByteArrayInputStream bais = new ByteArrayInputStream(reportExec.getExecResult());
+ ZipInputStream zis = new ZipInputStream(bais);
+ try {
+ // a single ZipEntry in the ZipInputStream (see ReportJob)
+ zis.getNextEntry();
+
+ Pipeline<SAXPipelineComponent> pipeline = new NonCachingPipeline<SAXPipelineComponent>();
+ pipeline.addComponent(new XMLGenerator(zis));
+
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ parameters.put("status", reportExec.getStatus());
+ parameters.put("message", reportExec.getMessage());
+ parameters.put("startDate", reportExec.getStartDate());
+ parameters.put("endDate", reportExec.getEndDate());
+
+ switch (format) {
+ case HTML:
+ XSLTTransformer xsl2html = new XSLTTransformer(getClass().getResource("/report/report2html.xsl"));
+ xsl2html.setParameters(parameters);
+ pipeline.addComponent(xsl2html);
+ pipeline.addComponent(XMLSerializer.createXHTMLSerializer());
+ break;
+
+ case PDF:
+ XSLTTransformer xsl2pdf = new XSLTTransformer(getClass().getResource("/report/report2fo.xsl"));
+ xsl2pdf.setParameters(parameters);
+ pipeline.addComponent(xsl2pdf);
+ pipeline.addComponent(new FopSerializer(MimeConstants.MIME_PDF));
+ break;
+
+ case RTF:
+ XSLTTransformer xsl2rtf = new XSLTTransformer(getClass().getResource("/report/report2fo.xsl"));
+ xsl2rtf.setParameters(parameters);
+ pipeline.addComponent(xsl2rtf);
+ pipeline.addComponent(new FopSerializer(MimeConstants.MIME_RTF));
+ break;
+
+ case CSV:
+ XSLTTransformer xsl2csv = new XSLTTransformer(getClass().getResource("/report/report2csv.xsl"));
+ xsl2csv.setParameters(parameters);
+ pipeline.addComponent(xsl2csv);
+ pipeline.addComponent(new TextSerializer());
+ break;
+
+ case XML:
+ default:
+ pipeline.addComponent(XMLSerializer.createXMLSerializer());
+ }
+
+ pipeline.setup(os);
+ pipeline.execute();
+
+ LOG.debug("Result of {} successfully exported as {}", reportExec, format);
+ } catch (Exception e) {
+ LOG.error("While exporting content", e);
+ } finally {
+ IOUtils.closeQuietly(zis);
+ IOUtils.closeQuietly(bais);
+ }
+ }
+
+ @PreAuthorize("hasRole('REPORT_READ')")
+ public ReportExec getAndCheckReportExec(final Long executionId) {
+ ReportExec reportExec = reportExecDAO.find(executionId);
+ if (reportExec == null) {
+ throw new NotFoundException("Report execution " + executionId);
+ }
+ if (!ReportExecStatus.SUCCESS.name().equals(reportExec.getStatus()) || reportExec.getExecResult() == null) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidReportExec);
+ sce.getElements().add(reportExec.getExecResult() == null
+ ? "No report data produced"
+ : "Report did not run successfully");
+ throw sce;
+ }
+ return reportExec;
+ }
+
+ @PreAuthorize("hasRole('REPORT_EXECUTE')")
+ public ReportExecTO execute(final Long reportId) {
+ Report report = reportDAO.find(reportId);
+ if (report == null) {
+ throw new NotFoundException("Report " + reportId);
+ }
+
+ try {
+ jobInstanceLoader.registerJob(report);
+
+ scheduler.getScheduler().triggerJob(
+ new JobKey(JobInstanceLoader.getJobName(report), Scheduler.DEFAULT_GROUP));
+ } catch (Exception e) {
+ LOG.error("While executing report {}", report, e);
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Scheduling);
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
+
+ ReportExecTO result = new ReportExecTO();
+ result.setReport(reportId);
+ result.setStartDate(new Date());
+ result.setStatus(ReportExecStatus.STARTED.name());
+ result.setMessage("Job fired; waiting for results...");
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('REPORT_DELETE')")
+ public ReportTO delete(final Long reportId) {
+ Report report = reportDAO.find(reportId);
+ if (report == null) {
+ throw new NotFoundException("Report " + reportId);
+ }
+
+ ReportTO deletedReport = binder.getReportTO(report);
+ jobInstanceLoader.unregisterJob(report);
+ reportDAO.delete(report);
+ return deletedReport;
+ }
+
+ @PreAuthorize("hasRole('REPORT_DELETE')")
+ public ReportExecTO deleteExecution(final Long executionId) {
+ ReportExec reportExec = reportExecDAO.find(executionId);
+ if (reportExec == null) {
+ throw new NotFoundException("Report execution " + executionId);
+ }
+
+ ReportExecTO reportExecToDelete = binder.getReportExecTO(reportExec);
+ reportExecDAO.delete(reportExec);
+ return reportExecToDelete;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ReportTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ Long id = null;
+
+ if (ArrayUtils.isNotEmpty(args) && ("create".equals(method.getName())
+ || "update".equals(method.getName())
+ || "delete".equals(method.getName()))) {
+ for (int i = 0; id == null && i < args.length; i++) {
+ if (args[i] instanceof Long) {
+ id = (Long) args[i];
+ } else if (args[i] instanceof ReportTO) {
+ id = ((ReportTO) args[i]).getId();
+ }
+ }
+ }
+
+ if ((id != null) && !id.equals(0l)) {
+ try {
+ return binder.getReportTO(reportDAO.find(id));
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ResourceLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ResourceLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ResourceLogic.java
new file mode 100644
index 0000000..d1b2851
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ResourceLogic.java
@@ -0,0 +1,301 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.persistence.api.dao.ConnInstanceDAO;
+import org.apache.syncope.persistence.api.dao.DuplicateException;
+import org.apache.syncope.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.dao.UserDAO;
+import org.apache.syncope.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
+import org.apache.syncope.persistence.api.entity.ConnInstance;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.MappingItem;
+import org.apache.syncope.persistence.api.entity.Subject;
+import org.apache.syncope.provisioning.api.Connector;
+import org.apache.syncope.provisioning.api.ConnectorFactory;
+import org.apache.syncope.server.logic.data.ResourceDataBinder;
+import org.apache.syncope.server.logic.init.ImplementationClassNamesLoader;
+import org.apache.syncope.server.utils.ConnObjectUtil;
+import org.apache.syncope.server.utils.MappingUtil;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.AttributeUtil;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.Name;
+import org.identityconnectors.framework.common.objects.ObjectClass;
+import org.identityconnectors.framework.common.objects.Uid;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class ResourceLogic extends AbstractTransactionalLogic<ResourceTO> {
+
+ @Autowired
+ private ExternalResourceDAO resourceDAO;
+
+ @Autowired
+ private ConnInstanceDAO connInstanceDAO;
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private RoleDAO roleDAO;
+
+ @Autowired
+ private ResourceDataBinder binder;
+
+ @Autowired
+ private ImplementationClassNamesLoader classNamesLoader;
+
+ @Autowired
+ private ConnObjectUtil connObjectUtil;
+
+ @Autowired
+ private ConnectorFactory connFactory;
+
+ @Autowired
+ private AttributableUtilFactory attrUtilFactory;
+
+ @PreAuthorize("hasRole('RESOURCE_CREATE')")
+ public ResourceTO create(final ResourceTO resourceTO) {
+ if (StringUtils.isBlank(resourceTO.getKey())) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+ sce.getElements().add("Resource name");
+ throw sce;
+ }
+
+ if (resourceDAO.find(resourceTO.getKey()) != null) {
+ throw new DuplicateException("Resource '" + resourceTO.getKey() + "'");
+ }
+
+ ExternalResource resource = null;
+ try {
+ resource = resourceDAO.save(binder.create(resourceTO));
+ } catch (SyncopeClientException e) {
+ throw e;
+ } catch (Exception e) {
+ SyncopeClientException ex = SyncopeClientException.build(ClientExceptionType.InvalidExternalResource);
+ ex.getElements().add(e.getMessage());
+ throw ex;
+ }
+
+ return binder.getResourceTO(resource);
+ }
+
+ @PreAuthorize("hasRole('RESOURCE_UPDATE')")
+ public ResourceTO update(final ResourceTO resourceTO) {
+ ExternalResource resource = resourceDAO.find(resourceTO.getKey());
+ if (resource == null) {
+ throw new NotFoundException("Resource '" + resourceTO.getKey() + "'");
+ }
+
+ resource = binder.update(resource, resourceTO);
+ try {
+ resource = resourceDAO.save(resource);
+ } catch (SyncopeClientException e) {
+ throw e;
+ } catch (Exception e) {
+ SyncopeClientException ex = SyncopeClientException.build(ClientExceptionType.InvalidExternalResource);
+ ex.getElements().add(e.getMessage());
+ throw ex;
+ }
+
+ return binder.getResourceTO(resource);
+ }
+
+ @PreAuthorize("hasRole('RESOURCE_DELETE')")
+ public ResourceTO delete(final String resourceName) {
+ ExternalResource resource = resourceDAO.find(resourceName);
+ if (resource == null) {
+ throw new NotFoundException("Resource '" + resourceName + "'");
+ }
+
+ ResourceTO resourceToDelete = binder.getResourceTO(resource);
+
+ resourceDAO.delete(resourceName);
+
+ return resourceToDelete;
+ }
+
+ @PreAuthorize("hasRole('RESOURCE_READ')")
+ @Transactional(readOnly = true)
+ public ResourceTO read(final String resourceName) {
+ ExternalResource resource = resourceDAO.find(resourceName);
+ if (resource == null) {
+ throw new NotFoundException("Resource '" + resourceName + "'");
+ }
+
+ return binder.getResourceTO(resource);
+ }
+
+ @PreAuthorize("hasRole('RESOURCE_READ')")
+ public Set<String> getPropagationActionsClasses() {
+ Set<String> actionsClasses = classNamesLoader.getClassNames(
+ ImplementationClassNamesLoader.Type.PROPAGATION_ACTIONS);
+
+ return actionsClasses;
+ }
+
+ @PreAuthorize("isAuthenticated()")
+ @Transactional(readOnly = true)
+ public List<ResourceTO> list(final Long connInstanceId) {
+ List<? extends ExternalResource> resources;
+
+ if (connInstanceId == null) {
+ resources = resourceDAO.findAll();
+ } else {
+ ConnInstance connInstance = connInstanceDAO.find(connInstanceId);
+ resources = connInstance.getResources();
+ }
+
+ return binder.getResourceTOs(resources);
+ }
+
+ @PreAuthorize("hasRole('RESOURCE_GETCONNECTOROBJECT')")
+ @Transactional(readOnly = true)
+ public ConnObjectTO getConnectorObject(final String resourceName, final SubjectType type, final Long id) {
+ ExternalResource resource = resourceDAO.find(resourceName);
+ if (resource == null) {
+ throw new NotFoundException("Resource '" + resourceName + "'");
+ }
+
+ Subject<?, ?, ?> subject = type == SubjectType.USER
+ ? userDAO.find(id)
+ : roleDAO.find(id);
+ if (subject == null) {
+ throw new NotFoundException(type + " " + id);
+ }
+
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(type.asAttributableType());
+
+ MappingItem accountIdItem = attrUtil.getAccountIdItem(resource);
+ if (accountIdItem == null) {
+ throw new NotFoundException("AccountId mapping for " + type + " " + id + " on resource '" + resourceName
+ + "'");
+ }
+ final String accountIdValue = MappingUtil.getAccountIdValue(
+ subject, resource, attrUtil.getAccountIdItem(resource));
+
+ final ObjectClass objectClass = SubjectType.USER == type ? ObjectClass.ACCOUNT : ObjectClass.GROUP;
+
+ final Connector connector = connFactory.getConnector(resource);
+ final ConnectorObject connectorObject = connector.getObject(objectClass, new Uid(accountIdValue),
+ connector.getOperationOptions(attrUtil.getMappingItems(resource, MappingPurpose.BOTH)));
+ if (connectorObject == null) {
+ throw new NotFoundException("Object " + accountIdValue + " with class " + objectClass
+ + "not found on resource " + resourceName);
+ }
+
+ final Set<Attribute> attributes = connectorObject.getAttributes();
+ if (AttributeUtil.find(Uid.NAME, attributes) == null) {
+ attributes.add(connectorObject.getUid());
+ }
+ if (AttributeUtil.find(Name.NAME, attributes) == null) {
+ attributes.add(connectorObject.getName());
+ }
+
+ return connObjectUtil.getConnObjectTO(connectorObject);
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_READ')")
+ @Transactional(readOnly = true)
+ public boolean check(final ResourceTO resourceTO) {
+ final ConnInstance connInstance = binder.getConnInstance(resourceTO);
+
+ final Connector connector = connFactory.createConnector(connInstance, connInstance.getConfiguration());
+
+ boolean result;
+ try {
+ connector.test();
+ result = true;
+ } catch (Exception e) {
+ LOG.error("Test connection failure {}", e);
+ result = false;
+ }
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('RESOURCE_DELETE') and #bulkAction.operation == #bulkAction.operation.DELETE")
+ public BulkActionResult bulk(final BulkAction bulkAction) {
+ BulkActionResult res = new BulkActionResult();
+
+ if (bulkAction.getOperation() == BulkAction.Type.DELETE) {
+ for (String name : bulkAction.getTargets()) {
+ try {
+ res.add(delete(name).getKey(), BulkActionResult.Status.SUCCESS);
+ } catch (Exception e) {
+ LOG.error("Error performing delete for resource {}", name, e);
+ res.add(name, BulkActionResult.Status.FAILURE);
+ }
+ }
+ }
+
+ return res;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ResourceTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ String name = null;
+
+ if (ArrayUtils.isNotEmpty(args)) {
+ for (int i = 0; name == null && i < args.length; i++) {
+ if (args[i] instanceof String) {
+ name = (String) args[i];
+ } else if (args[i] instanceof ResourceTO) {
+ name = ((ResourceTO) args[i]).getKey();
+ }
+ }
+ }
+
+ if (name != null) {
+ try {
+ return binder.getResourceTO(resourceDAO.find(name));
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/RoleLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/RoleLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/RoleLogic.java
new file mode 100644
index 0000000..aee0d27
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/RoleLogic.java
@@ -0,0 +1,405 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Resource;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.persistence.api.RoleEntitlementUtil;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.dao.SubjectSearchDAO;
+import org.apache.syncope.persistence.api.dao.UserDAO;
+import org.apache.syncope.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.provisioning.api.AttributableTransformer;
+import org.apache.syncope.provisioning.api.RoleProvisioningManager;
+import org.apache.syncope.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.server.logic.data.RoleDataBinder;
+import org.apache.syncope.server.security.AuthContextUtil;
+import org.apache.syncope.server.security.UnauthorizedRoleException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionInterceptor;
+
+/**
+ * Note that this controller does not extend {@link AbstractTransactionalLogic}, hence does not provide any
+ * Spring's Transactional logic at class level.
+ */
+@Component
+public class RoleLogic extends AbstractSubjectLogic<RoleTO, RoleMod> {
+
+ @Autowired
+ protected RoleDAO roleDAO;
+
+ @Autowired
+ protected UserDAO userDAO;
+
+ @Autowired
+ protected SubjectSearchDAO searchDAO;
+
+ @Autowired
+ protected RoleDataBinder binder;
+
+ @Autowired
+ protected PropagationManager propagationManager;
+
+ @Autowired
+ protected PropagationTaskExecutor taskExecutor;
+
+ @Autowired
+ protected AttributableTransformer attrTransformer;
+
+ @Resource(name = "anonymousUser")
+ protected String anonymousUser;
+
+ @Autowired
+ protected RoleProvisioningManager provisioningManager;
+
+ @PreAuthorize("hasAnyRole('ROLE_READ', T(org.apache.syncope.common.lib.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")
+ @Transactional(readOnly = true)
+ @Override
+ public RoleTO read(final Long roleKey) {
+ Role role;
+ // bypass role entitlements check
+ if (anonymousUser.equals(AuthContextUtil.getAuthenticatedUsername())) {
+ role = roleDAO.find(roleKey);
+ } else {
+ role = roleDAO.authFetchRole(roleKey);
+ }
+
+ if (role == null) {
+ throw new NotFoundException("Role " + roleKey);
+ }
+
+ return binder.getRoleTO(role);
+ }
+
+ @PreAuthorize("isAuthenticated() "
+ + "and not(hasRole(T(org.apache.syncope.common.lib.SyncopeConstants).ANONYMOUS_ENTITLEMENT))")
+ @Transactional(readOnly = true)
+ public RoleTO readSelf(final Long roleKey) {
+ // Explicit search instead of using binder.getRoleFromId() in order to bypass auth checks - will do here
+ Role role = roleDAO.find(roleKey);
+ if (role == null) {
+ throw new NotFoundException("Role " + roleKey);
+ }
+
+ Set<Long> ownedRoleIds;
+ User authUser = userDAO.find(AuthContextUtil.getAuthenticatedUsername());
+ if (authUser == null) {
+ ownedRoleIds = Collections.<Long>emptySet();
+ } else {
+ ownedRoleIds = authUser.getRoleIds();
+ }
+
+ Set<Long> allowedRoleIds = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
+ allowedRoleIds.addAll(ownedRoleIds);
+ if (!allowedRoleIds.contains(role.getKey())) {
+ throw new UnauthorizedRoleException(role.getKey());
+ }
+
+ return binder.getRoleTO(role);
+ }
+
+ @PreAuthorize("hasRole('ROLE_READ')")
+ @Transactional(readOnly = true)
+ public RoleTO parent(final Long roleKey) {
+ Role role = roleDAO.authFetchRole(roleKey);
+
+ Set<Long> allowedRoleIds = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
+ if (role.getParent() != null && !allowedRoleIds.contains(role.getParent().getKey())) {
+ throw new UnauthorizedRoleException(role.getParent().getKey());
+ }
+
+ RoleTO result = role.getParent() == null
+ ? null
+ : binder.getRoleTO(role.getParent());
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('ROLE_READ')")
+ @Transactional(readOnly = true)
+ public List<RoleTO> children(final Long roleKey) {
+ Role role = roleDAO.authFetchRole(roleKey);
+
+ Set<Long> allowedRoleIds = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
+
+ List<Role> children = roleDAO.findChildren(role);
+ List<RoleTO> childrenTOs = new ArrayList<RoleTO>(children.size());
+ for (Role child : children) {
+ if (allowedRoleIds.contains(child.getKey())) {
+ childrenTOs.add(binder.getRoleTO(child));
+ }
+ }
+
+ return childrenTOs;
+ }
+
+ @PreAuthorize("isAuthenticated()")
+ @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+ @Override
+ public int count() {
+ return roleDAO.count();
+ }
+
+ @PreAuthorize("isAuthenticated()")
+ @Transactional(readOnly = true)
+ @Override
+ public List<RoleTO> list(final int page, final int size, final List<OrderByClause> orderBy) {
+ List<Role> roles = roleDAO.findAll(page, size, orderBy);
+
+ List<RoleTO> roleTOs = new ArrayList<>(roles.size());
+ for (Role role : roles) {
+ roleTOs.add(binder.getRoleTO(role));
+ }
+
+ return roleTOs;
+ }
+
+ @PreAuthorize("isAuthenticated()")
+ @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+ @Override
+ public int searchCount(final SearchCond searchCondition) {
+ final Set<Long> adminRoleIds = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
+ return searchDAO.count(adminRoleIds, searchCondition, SubjectType.ROLE);
+ }
+
+ @PreAuthorize("isAuthenticated()")
+ @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+ @Override
+ public List<RoleTO> search(final SearchCond searchCondition, final int page, final int size,
+ final List<OrderByClause> orderBy) {
+
+ final List<Role> matchingRoles = searchDAO.search(
+ RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames()),
+ searchCondition, page, size, orderBy, SubjectType.ROLE);
+
+ final List<RoleTO> result = new ArrayList<>(matchingRoles.size());
+ for (Role role : matchingRoles) {
+ result.add(binder.getRoleTO(role));
+ }
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('ROLE_CREATE')")
+ public RoleTO create(final RoleTO roleTO) {
+ // Check that this operation is allowed to be performed by caller
+ Set<Long> allowedRoleIds = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
+ if (roleTO.getParent() != 0 && !allowedRoleIds.contains(roleTO.getParent())) {
+ throw new UnauthorizedRoleException(roleTO.getParent());
+ }
+
+ // Attributable transformation (if configured)
+ RoleTO actual = attrTransformer.transform(roleTO);
+ LOG.debug("Transformed: {}", actual);
+
+ /*
+ * Actual operations: workflow, propagation
+ */
+ Map.Entry<Long, List<PropagationStatus>> created = provisioningManager.create(roleTO);
+ final RoleTO savedTO = binder.getRoleTO(created.getKey());
+ savedTO.getPropagationStatusTOs().addAll(created.getValue());
+ return savedTO;
+ }
+
+ @PreAuthorize("hasRole('ROLE_UPDATE')")
+ @Override
+ public RoleTO update(final RoleMod roleMod) {
+ // Check that this operation is allowed to be performed by caller
+ roleDAO.authFetchRole(roleMod.getKey());
+
+ // Attribute value transformation (if configured)
+ RoleMod actual = attrTransformer.transform(roleMod);
+ LOG.debug("Transformed: {}", actual);
+
+ Map.Entry<Long, List<PropagationStatus>> updated = provisioningManager.update(roleMod);
+
+ final RoleTO updatedTO = binder.getRoleTO(updated.getKey());
+ updatedTO.getPropagationStatusTOs().addAll(updated.getValue());
+ return updatedTO;
+ }
+
+ @PreAuthorize("hasRole('ROLE_DELETE')")
+ @Override
+ public RoleTO delete(final Long roleKey) {
+ List<Role> ownedRoles = roleDAO.findOwnedByRole(roleKey);
+ if (!ownedRoles.isEmpty()) {
+ List<String> owned = new ArrayList<String>(ownedRoles.size());
+ for (Role role : ownedRoles) {
+ owned.add(role.getKey() + " " + role.getName());
+ }
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RoleOwnership);
+ sce.getElements().addAll(owned);
+ throw sce;
+ }
+
+ List<PropagationStatus> statuses = provisioningManager.delete(roleKey);
+
+ RoleTO roleTO = new RoleTO();
+ roleTO.setKey(roleKey);
+
+ roleTO.getPropagationStatusTOs().addAll(statuses);
+
+ return roleTO;
+ }
+
+ @PreAuthorize("(hasRole('ROLE_DELETE') and #bulkAction.operation == #bulkAction.operation.DELETE)")
+ public BulkActionResult bulk(final BulkAction bulkAction) {
+ BulkActionResult res = new BulkActionResult();
+
+ if (bulkAction.getOperation() == BulkAction.Type.DELETE) {
+ for (String roleKey : bulkAction.getTargets()) {
+ try {
+ res.add(delete(Long.valueOf(roleKey)).getKey(), BulkActionResult.Status.SUCCESS);
+ } catch (Exception e) {
+ LOG.error("Error performing delete for role {}", roleKey, e);
+ res.add(roleKey, BulkActionResult.Status.FAILURE);
+ }
+ }
+ } else {
+ LOG.warn("Unsupported bulk action: {}", bulkAction.getOperation());
+ }
+
+ return res;
+ }
+
+ @PreAuthorize("hasRole('ROLE_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public RoleTO unlink(final Long roleKey, final Collection<String> resources) {
+ final RoleMod roleMod = new RoleMod();
+ roleMod.setKey(roleKey);
+ roleMod.getResourcesToRemove().addAll(resources);
+ final Long updatedResult = provisioningManager.unlink(roleMod);
+
+ return binder.getRoleTO(updatedResult);
+ }
+
+ @PreAuthorize("hasRole('ROLE_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public RoleTO link(final Long roleKey, final Collection<String> resources) {
+ final RoleMod roleMod = new RoleMod();
+ roleMod.setKey(roleKey);
+ roleMod.getResourcesToAdd().addAll(resources);
+ return binder.getRoleTO(provisioningManager.link(roleMod));
+ }
+
+ @PreAuthorize("hasRole('ROLE_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public RoleTO unassign(final Long roleKey, final Collection<String> resources) {
+ final RoleMod roleMod = new RoleMod();
+ roleMod.setKey(roleKey);
+ roleMod.getResourcesToRemove().addAll(resources);
+ return update(roleMod);
+ }
+
+ @PreAuthorize("hasRole('ROLE_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public RoleTO assign(
+ final Long roleKey, final Collection<String> resources, final boolean changePwd, final String password) {
+
+ final RoleMod userMod = new RoleMod();
+ userMod.setKey(roleKey);
+ userMod.getResourcesToAdd().addAll(resources);
+ return update(userMod);
+ }
+
+ @PreAuthorize("hasRole('ROLE_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public RoleTO deprovision(final Long roleKey, final Collection<String> resources) {
+ final Role role = roleDAO.authFetchRole(roleKey);
+
+ List<PropagationStatus> statuses = provisioningManager.deprovision(roleKey, resources);
+
+ final RoleTO updatedTO = binder.getRoleTO(role);
+ updatedTO.getPropagationStatusTOs().addAll(statuses);
+ return updatedTO;
+ }
+
+ @PreAuthorize("hasRole('ROLE_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public RoleTO provision(
+ final Long roleKey, final Collection<String> resources, final boolean changePwd, final String password) {
+ final RoleTO original = binder.getRoleTO(roleKey);
+
+ //trick: assign and retrieve propagation statuses ...
+ original.getPropagationStatusTOs().addAll(
+ assign(roleKey, resources, changePwd, password).getPropagationStatusTOs());
+
+ // .... rollback.
+ TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
+ return original;
+ }
+
+ @Override
+ protected RoleTO resolveReference(final Method method, final Object... args) throws UnresolvedReferenceException {
+ Long id = null;
+
+ if (ArrayUtils.isNotEmpty(args)) {
+ for (int i = 0; id == null && i < args.length; i++) {
+ if (args[i] instanceof Long) {
+ id = (Long) args[i];
+ } else if (args[i] instanceof RoleTO) {
+ id = ((RoleTO) args[i]).getKey();
+ } else if (args[i] instanceof RoleMod) {
+ id = ((RoleMod) args[i]).getKey();
+ }
+ }
+ }
+
+ if ((id != null) && !id.equals(0l)) {
+ try {
+ return binder.getRoleTO(id);
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/SchemaLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/SchemaLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/SchemaLogic.java
new file mode 100644
index 0000000..675bd42
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/SchemaLogic.java
@@ -0,0 +1,328 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.to.DerSchemaTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.VirSchemaTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.syncope.persistence.api.dao.DerSchemaDAO;
+import org.apache.syncope.persistence.api.dao.DuplicateException;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
+import org.apache.syncope.persistence.api.entity.DerSchema;
+import org.apache.syncope.persistence.api.entity.PlainSchema;
+import org.apache.syncope.persistence.api.entity.VirSchema;
+import org.apache.syncope.server.logic.data.SchemaDataBinder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SchemaLogic extends AbstractTransactionalLogic<AbstractSchemaTO> {
+
+ @Autowired
+ private PlainSchemaDAO plainSchemaDAO;
+
+ @Autowired
+ private DerSchemaDAO derSchemaDAO;
+
+ @Autowired
+ private VirSchemaDAO virSchemaDAO;
+
+ @Autowired
+ private SchemaDataBinder binder;
+
+ @Autowired
+ private AttributableUtilFactory attrUtilFactory;
+
+ private boolean doesSchemaExist(final SchemaType schemaType, final String name, final AttributableUtil attrUtil) {
+ boolean found;
+
+ switch (schemaType) {
+ case VIRTUAL:
+ found = virSchemaDAO.find(name, attrUtil.virSchemaClass()) != null;
+ break;
+
+ case DERIVED:
+ found = derSchemaDAO.find(name, attrUtil.derSchemaClass()) != null;
+ break;
+
+ case PLAIN:
+ found = plainSchemaDAO.find(name, attrUtil.plainSchemaClass()) != null;
+ break;
+
+ default:
+ found = false;
+ }
+
+ return found;
+ }
+
+ @PreAuthorize("hasRole('SCHEMA_CREATE')")
+ @SuppressWarnings("unchecked")
+ public <T extends AbstractSchemaTO> T create(
+ final AttributableType attrType, final SchemaType schemaType, final T schemaTO) {
+
+ if (StringUtils.isBlank(schemaTO.getKey())) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+ sce.getElements().add("Schema name");
+ throw sce;
+ }
+
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(attrType);
+
+ if (doesSchemaExist(schemaType, schemaTO.getKey(), attrUtil)) {
+ throw new DuplicateException(schemaType + "/" + attrType + "/" + schemaTO.getKey());
+ }
+
+ T created;
+ switch (schemaType) {
+ case VIRTUAL:
+ VirSchema virSchema = attrUtil.newVirSchema();
+ binder.create((VirSchemaTO) schemaTO, virSchema);
+ virSchema = virSchemaDAO.save(virSchema);
+ created = (T) binder.getVirSchemaTO(virSchema);
+ break;
+ case DERIVED:
+ DerSchema derSchema = attrUtil.newDerSchema();
+ binder.create((DerSchemaTO) schemaTO, derSchema);
+ derSchema = derSchemaDAO.save(derSchema);
+
+ created = (T) binder.getDerSchemaTO(derSchema);
+ break;
+
+ case PLAIN:
+ default:
+ PlainSchema normalSchema = attrUtil.newPlainSchema();
+ binder.create((PlainSchemaTO) schemaTO, normalSchema);
+ normalSchema = plainSchemaDAO.save(normalSchema);
+
+ created = (T) binder.getSchemaTO(normalSchema, attrUtil);
+ }
+ return created;
+ }
+
+ @PreAuthorize("hasRole('SCHEMA_DELETE')")
+ public void delete(final AttributableType attrType, final SchemaType schemaType, final String schemaName) {
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(attrType);
+
+ if (!doesSchemaExist(schemaType, schemaName, attrUtil)) {
+ throw new NotFoundException(schemaType + "/" + attrType + "/" + schemaName);
+ }
+
+ switch (schemaType) {
+ case VIRTUAL:
+ virSchemaDAO.delete(schemaName, attrUtil);
+ break;
+
+ case DERIVED:
+ derSchemaDAO.delete(schemaName, attrUtil);
+ break;
+
+ case PLAIN:
+ default:
+ plainSchemaDAO.delete(schemaName, attrUtil);
+ }
+ }
+
+ @PreAuthorize("isAuthenticated()")
+ @SuppressWarnings("unchecked")
+ public <T extends AbstractSchemaTO> List<T> list(final AttributableType attrType, final SchemaType schemaType) {
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(attrType);
+
+ List<T> result;
+ switch (schemaType) {
+ case VIRTUAL:
+ List<VirSchema> virSchemas = virSchemaDAO.findAll(attrUtil.virSchemaClass());
+ result = new ArrayList<>(virSchemas.size());
+ for (VirSchema derSchema : virSchemas) {
+ result.add((T) binder.getVirSchemaTO(derSchema));
+ }
+ break;
+
+ case DERIVED:
+ List<DerSchema> derSchemas = derSchemaDAO.findAll(attrUtil.derSchemaClass());
+ result = new ArrayList<>(derSchemas.size());
+ for (DerSchema derSchema : derSchemas) {
+ result.add((T) binder.getDerSchemaTO(derSchema));
+ }
+ break;
+
+ case PLAIN:
+ default:
+ List<PlainSchema> schemas = plainSchemaDAO.findAll(attrUtil.plainSchemaClass());
+ result = new ArrayList<>(schemas.size());
+ for (PlainSchema schema : schemas) {
+ result.add((T) binder.getSchemaTO(schema, attrUtil));
+ }
+ }
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('SCHEMA_READ')")
+ @SuppressWarnings("unchecked")
+ public <T extends AbstractSchemaTO> T read(
+ final AttributableType attrType, final SchemaType schemaType, final String schemaName) {
+
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(attrType);
+
+ T read;
+ switch (schemaType) {
+ case VIRTUAL:
+ VirSchema virSchema = virSchemaDAO.find(schemaName, attrUtil.virSchemaClass());
+ if (virSchema == null) {
+ throw new NotFoundException("Virtual Schema '" + schemaName + "'");
+ }
+
+ read = (T) binder.getVirSchemaTO(virSchema);
+ break;
+
+ case DERIVED:
+ DerSchema derSchema = derSchemaDAO.find(schemaName, attrUtil.derSchemaClass());
+ if (derSchema == null) {
+ throw new NotFoundException("Derived schema '" + schemaName + "'");
+ }
+
+ read = (T) binder.getDerSchemaTO(derSchema);
+ break;
+
+ case PLAIN:
+ default:
+ PlainSchema schema = plainSchemaDAO.find(schemaName, attrUtil.plainSchemaClass());
+ if (schema == null) {
+ throw new NotFoundException("Schema '" + schemaName + "'");
+ }
+
+ read = (T) binder.getSchemaTO(schema, attrUtil);
+ }
+
+ return read;
+ }
+
+ @PreAuthorize("hasRole('SCHEMA_UPDATE')")
+ public <T extends AbstractSchemaTO> void update(
+ final AttributableType attrType, final SchemaType schemaType, final T schemaTO) {
+
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(attrType);
+
+ if (!doesSchemaExist(schemaType, schemaTO.getKey(), attrUtil)) {
+ throw new NotFoundException(schemaType + "/" + attrType + "/" + schemaTO.getKey());
+ }
+
+ switch (schemaType) {
+ case VIRTUAL:
+ VirSchema virSchema = virSchemaDAO.find(schemaTO.getKey(), attrUtil.virSchemaClass());
+ if (virSchema == null) {
+ throw new NotFoundException("Virtual Schema '" + schemaTO.getKey() + "'");
+ }
+
+ binder.update((VirSchemaTO) schemaTO, virSchema);
+ virSchemaDAO.save(virSchema);
+ break;
+
+ case DERIVED:
+ DerSchema derSchema = derSchemaDAO.find(schemaTO.getKey(), attrUtil.derSchemaClass());
+ if (derSchema == null) {
+ throw new NotFoundException("Derived schema '" + schemaTO.getKey() + "'");
+ }
+
+ binder.update((DerSchemaTO) schemaTO, derSchema);
+ derSchemaDAO.save(derSchema);
+ break;
+
+ case PLAIN:
+ default:
+ PlainSchema schema = plainSchemaDAO.find(schemaTO.getKey(), attrUtil.plainSchemaClass());
+ if (schema == null) {
+ throw new NotFoundException("Schema '" + schemaTO.getKey() + "'");
+ }
+
+ binder.update((PlainSchemaTO) schemaTO, schema, attrUtil);
+ plainSchemaDAO.save(schema);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected AbstractSchemaTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ String kind = null;
+ String name = null;
+ if (ArrayUtils.isNotEmpty(args)) {
+ for (int i = 0; (name == null || kind == null) && i < args.length; i++) {
+ if (args[i] instanceof String) {
+ if (kind == null) {
+ kind = (String) args[i];
+ } else {
+ name = (String) args[i];
+ }
+ } else if (args[i] instanceof AbstractSchemaTO) {
+ name = ((AbstractSchemaTO) args[i]).getKey();
+ }
+ }
+ }
+
+ if (name != null) {
+ try {
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(kind);
+
+ AbstractSchemaTO result = null;
+
+ PlainSchema plainSchema = plainSchemaDAO.find(name, attrUtil.plainSchemaClass());
+ if (plainSchema == null) {
+ DerSchema derSchema = derSchemaDAO.find(name, attrUtil.derSchemaClass());
+ if (derSchema == null) {
+ VirSchema virSchema = virSchemaDAO.find(name, attrUtil.virSchemaClass());
+ if (virSchema != null) {
+ result = binder.getVirSchemaTO(virSchema);
+ }
+ } else {
+ result = binder.getDerSchemaTO(derSchema);
+ }
+ } else {
+ result = binder.getSchemaTO(plainSchema, attrUtil);
+ }
+
+ return result;
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/SecurityQuestionLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/SecurityQuestionLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/SecurityQuestionLogic.java
new file mode 100644
index 0000000..01b2a57
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/SecurityQuestionLogic.java
@@ -0,0 +1,150 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.to.SecurityQuestionTO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.SecurityQuestionDAO;
+import org.apache.syncope.persistence.api.dao.UserDAO;
+import org.apache.syncope.persistence.api.entity.user.SecurityQuestion;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.server.logic.data.SecurityQuestionDataBinder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SecurityQuestionLogic extends AbstractTransactionalLogic<SecurityQuestionTO> {
+
+ @Autowired
+ private SecurityQuestionDAO securityQuestionDAO;
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private SecurityQuestionDataBinder binder;
+
+ @PreAuthorize("isAuthenticated()")
+ public List<SecurityQuestionTO> list() {
+ List<SecurityQuestionTO> result = new ArrayList<SecurityQuestionTO>();
+ for (SecurityQuestion securityQuestion : securityQuestionDAO.findAll()) {
+ result.add(binder.getSecurityQuestionTO(securityQuestion));
+ }
+
+ return result;
+ }
+
+ @PreAuthorize("isAuthenticated()")
+ public SecurityQuestionTO read(final Long securityQuestionId) {
+ SecurityQuestion securityQuestion = securityQuestionDAO.find(securityQuestionId);
+ if (securityQuestion == null) {
+ LOG.error("Could not find security question '" + securityQuestionId + "'");
+
+ throw new NotFoundException(String.valueOf(securityQuestionId));
+ }
+
+ return binder.getSecurityQuestionTO(securityQuestion);
+ }
+
+ @PreAuthorize("hasRole('SECURITY_QUESTION_CREATE')")
+ public SecurityQuestionTO create(final SecurityQuestionTO securityQuestionTO) {
+ return binder.getSecurityQuestionTO(securityQuestionDAO.save(binder.create(securityQuestionTO)));
+ }
+
+ @PreAuthorize("hasRole('SECURITY_QUESTION_UPDATE')")
+ public SecurityQuestionTO update(final SecurityQuestionTO securityQuestionTO) {
+ SecurityQuestion securityQuestion = securityQuestionDAO.find(securityQuestionTO.getKey());
+ if (securityQuestion == null) {
+ LOG.error("Could not find security question '" + securityQuestionTO.getKey() + "'");
+
+ throw new NotFoundException(String.valueOf(securityQuestionTO.getKey()));
+ }
+
+ binder.update(securityQuestion, securityQuestionTO);
+ securityQuestion = securityQuestionDAO.save(securityQuestion);
+
+ return binder.getSecurityQuestionTO(securityQuestion);
+ }
+
+ @PreAuthorize("hasRole('SECURITY_QUESTION_DELETE')")
+ public SecurityQuestionTO delete(final Long securityQuestionId) {
+ SecurityQuestion securityQuestion = securityQuestionDAO.find(securityQuestionId);
+ if (securityQuestion == null) {
+ LOG.error("Could not find security question '" + securityQuestionId + "'");
+
+ throw new NotFoundException(String.valueOf(securityQuestionId));
+ }
+
+ SecurityQuestionTO deleted = binder.getSecurityQuestionTO(securityQuestion);
+ securityQuestionDAO.delete(securityQuestionId);
+ return deleted;
+ }
+
+ @PreAuthorize("isAnonymous() or hasRole(T(org.apache.syncope.common.lib.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")
+ public SecurityQuestionTO read(final String username) {
+ if (username == null) {
+ throw new NotFoundException("Null username");
+ }
+ User user = userDAO.find(username);
+ if (user == null) {
+ throw new NotFoundException("User " + username);
+ }
+
+ if (user.getSecurityQuestion() == null) {
+ LOG.error("Could not find security question for user '" + username + "'");
+
+ throw new NotFoundException("Security question for user " + username);
+ }
+
+ return binder.getSecurityQuestionTO(user.getSecurityQuestion());
+ }
+
+ @Override
+ protected SecurityQuestionTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ Long id = null;
+
+ if (ArrayUtils.isNotEmpty(args)) {
+ for (int i = 0; id == null && i < args.length; i++) {
+ if (args[i] instanceof Long) {
+ id = (Long) args[i];
+ } else if (args[i] instanceof SecurityQuestionTO) {
+ id = ((SecurityQuestionTO) args[i]).getKey();
+ }
+ }
+ }
+
+ if ((id != null) && !id.equals(0l)) {
+ try {
+ return binder.getSecurityQuestionTO(securityQuestionDAO.find(id));
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/TaskLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/TaskLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/TaskLogic.java
new file mode 100644
index 0000000..11c9b4b
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/TaskLogic.java
@@ -0,0 +1,408 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.to.SyncTaskTO;
+import org.apache.syncope.common.lib.to.TaskExecTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.PropagationMode;
+import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.TaskDAO;
+import org.apache.syncope.persistence.api.dao.TaskExecDAO;
+import org.apache.syncope.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.persistence.api.entity.task.NotificationTask;
+import org.apache.syncope.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.persistence.api.entity.task.SchedTask;
+import org.apache.syncope.persistence.api.entity.task.Task;
+import org.apache.syncope.persistence.api.entity.task.TaskExec;
+import org.apache.syncope.persistence.api.entity.task.TaskUtil;
+import org.apache.syncope.persistence.api.entity.task.TaskUtilFactory;
+import org.apache.syncope.provisioning.api.job.TaskJob;
+import org.apache.syncope.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.server.logic.data.TaskDataBinder;
+import org.apache.syncope.server.logic.init.ImplementationClassNamesLoader;
+import org.apache.syncope.server.logic.init.JobInstanceLoader;
+import org.apache.syncope.server.logic.notification.NotificationJob;
+import org.quartz.JobDataMap;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TaskLogic extends AbstractTransactionalLogic<AbstractTaskTO> {
+
+ @Autowired
+ private TaskDAO taskDAO;
+
+ @Autowired
+ private TaskExecDAO taskExecDAO;
+
+ @Autowired
+ private TaskDataBinder binder;
+
+ @Autowired
+ private PropagationTaskExecutor taskExecutor;
+
+ @Autowired
+ private NotificationJob notificationJob;
+
+ @Autowired
+ private JobInstanceLoader jobInstanceLoader;
+
+ @Autowired
+ private SchedulerFactoryBean scheduler;
+
+ @Autowired
+ private ImplementationClassNamesLoader classNamesLoader;
+
+ @Autowired
+ private TaskUtilFactory taskUtilFactory;
+
+ @PreAuthorize("hasRole('TASK_CREATE')")
+ public <T extends SchedTaskTO> T createSchedTask(final T taskTO) {
+ TaskUtil taskUtil = taskUtilFactory.getInstance(taskTO);
+
+ SchedTask task = binder.createSchedTask(taskTO, taskUtil);
+ task = taskDAO.save(task);
+
+ try {
+ jobInstanceLoader.registerJob(task, task.getJobClassName(), task.getCronExpression());
+ } catch (Exception e) {
+ LOG.error("While registering quartz job for task " + task.getKey(), e);
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Scheduling);
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
+
+ return binder.getTaskTO(task, taskUtil);
+ }
+
+ @PreAuthorize("hasRole('TASK_UPDATE')")
+ public SyncTaskTO updateSync(final SyncTaskTO taskTO) {
+ return updateSched(taskTO);
+ }
+
+ @PreAuthorize("hasRole('TASK_UPDATE')")
+ public <T extends SchedTaskTO> T updateSched(final SchedTaskTO taskTO) {
+ SchedTask task = taskDAO.find(taskTO.getId());
+ if (task == null) {
+ throw new NotFoundException("Task " + taskTO.getId());
+ }
+
+ TaskUtil taskUtil = taskUtilFactory.getInstance(task);
+
+ binder.updateSchedTask(task, taskTO, taskUtil);
+ task = taskDAO.save(task);
+
+ try {
+ jobInstanceLoader.registerJob(task, task.getJobClassName(), task.getCronExpression());
+ } catch (Exception e) {
+ LOG.error("While registering quartz job for task " + task.getKey(), e);
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Scheduling);
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
+
+ return binder.getTaskTO(task, taskUtil);
+ }
+
+ @PreAuthorize("hasRole('TASK_LIST')")
+ public int count(final TaskType taskType) {
+ return taskDAO.count(taskType);
+ }
+
+ @PreAuthorize("hasRole('TASK_LIST')")
+ @SuppressWarnings("unchecked")
+ public <T extends AbstractTaskTO> List<T> list(final TaskType taskType,
+ final int page, final int size, final List<OrderByClause> orderByClauses) {
+
+ TaskUtil taskUtil = taskUtilFactory.getInstance(taskType);
+
+ List<Task> tasks = taskDAO.findAll(page, size, orderByClauses, taskType);
+ List<T> taskTOs = new ArrayList<>(tasks.size());
+ for (Task task : tasks) {
+ taskTOs.add((T) binder.getTaskTO(task, taskUtil));
+ }
+
+ return taskTOs;
+ }
+
+ @PreAuthorize("hasRole('TASK_LIST')")
+ public Set<String> getJobClasses() {
+ return classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.TASKJOB);
+ }
+
+ @PreAuthorize("hasRole('TASK_LIST')")
+ public Set<String> getSyncActionsClasses() {
+ return classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.SYNC_ACTIONS);
+ }
+
+ @PreAuthorize("hasRole('TASK_LIST')")
+ public Set<String> getPushActionsClasses() {
+ return classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.PUSH_ACTIONS);
+ }
+
+ @PreAuthorize("hasRole('TASK_READ')")
+ public <T extends AbstractTaskTO> T read(final Long taskId) {
+ Task task = taskDAO.find(taskId);
+ if (task == null) {
+ throw new NotFoundException("Task " + taskId);
+ }
+ return binder.getTaskTO(task, taskUtilFactory.getInstance(task));
+ }
+
+ @PreAuthorize("hasRole('TASK_READ')")
+ public TaskExecTO readExecution(final Long executionId) {
+ TaskExec taskExec = taskExecDAO.find(executionId);
+ if (taskExec == null) {
+ throw new NotFoundException("Task execution " + executionId);
+ }
+ return binder.getTaskExecTO(taskExec);
+ }
+
+ @PreAuthorize("hasRole('TASK_EXECUTE')")
+ public TaskExecTO execute(final Long taskId, final boolean dryRun) {
+ Task task = taskDAO.find(taskId);
+ if (task == null) {
+ throw new NotFoundException("Task " + taskId);
+ }
+ TaskUtil taskUtil = taskUtilFactory.getInstance(task);
+
+ TaskExecTO result = null;
+ switch (taskUtil.getType()) {
+ case PROPAGATION:
+ final TaskExec propExec = taskExecutor.execute((PropagationTask) task);
+ result = binder.getTaskExecTO(propExec);
+ break;
+
+ case NOTIFICATION:
+ final TaskExec notExec = notificationJob.executeSingle((NotificationTask) task);
+ result = binder.getTaskExecTO(notExec);
+ break;
+
+ case SCHEDULED:
+ case SYNCHRONIZATION:
+ case PUSH:
+ try {
+ jobInstanceLoader.registerJob(task,
+ ((SchedTask) task).getJobClassName(),
+ ((SchedTask) task).getCronExpression());
+
+ JobDataMap map = new JobDataMap();
+ map.put(TaskJob.DRY_RUN_JOBDETAIL_KEY, dryRun);
+
+ scheduler.getScheduler().triggerJob(
+ new JobKey(JobInstanceLoader.getJobName(task), Scheduler.DEFAULT_GROUP), map);
+ } catch (Exception e) {
+ LOG.error("While executing task {}", task, e);
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Scheduling);
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
+
+ result = new TaskExecTO();
+ result.setTask(taskId);
+ result.setStartDate(new Date());
+ result.setStatus("JOB_FIRED");
+ result.setMessage("Job fired; waiting for results...");
+ break;
+
+ default:
+ }
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('TASK_READ')")
+ public TaskExecTO report(final Long executionId, final PropagationTaskExecStatus status, final String message) {
+ TaskExec exec = taskExecDAO.find(executionId);
+ if (exec == null) {
+ throw new NotFoundException("Task execution " + executionId);
+ }
+
+ SyncopeClientException sce = SyncopeClientException.build(
+ ClientExceptionType.InvalidPropagationTaskExecReport);
+
+ TaskUtil taskUtil = taskUtilFactory.getInstance(exec.getTask());
+ if (TaskType.PROPAGATION == taskUtil.getType()) {
+ PropagationTask task = (PropagationTask) exec.getTask();
+ if (task.getPropagationMode() != PropagationMode.TWO_PHASES) {
+ sce.getElements().add("Propagation mode: " + task.getPropagationMode());
+ }
+ } else {
+ sce.getElements().add("Task type: " + taskUtil);
+ }
+
+ switch (status) {
+ case SUCCESS:
+ case FAILURE:
+ break;
+
+ case CREATED:
+ case SUBMITTED:
+ case UNSUBMITTED:
+ sce.getElements().add("Execution status to be set: " + status);
+ break;
+
+ default:
+ }
+
+ if (!sce.isEmpty()) {
+ throw sce;
+ }
+
+ exec.setStatus(status.toString());
+ exec.setMessage(message);
+ return binder.getTaskExecTO(taskExecDAO.save(exec));
+ }
+
+ @PreAuthorize("hasRole('TASK_DELETE')")
+ public <T extends AbstractTaskTO> T delete(final Long taskId) {
+ Task task = taskDAO.find(taskId);
+ if (task == null) {
+ throw new NotFoundException("Task " + taskId);
+ }
+ TaskUtil taskUtil = taskUtilFactory.getInstance(task);
+
+ T taskToDelete = binder.getTaskTO(task, taskUtil);
+
+ if (TaskType.SCHEDULED == taskUtil.getType()
+ || TaskType.SYNCHRONIZATION == taskUtil.getType()
+ || TaskType.PUSH == taskUtil.getType()) {
+ jobInstanceLoader.unregisterJob(task);
+ }
+
+ taskDAO.delete(task);
+ return taskToDelete;
+ }
+
+ @PreAuthorize("hasRole('TASK_DELETE')")
+ public TaskExecTO deleteExecution(final Long executionId) {
+ TaskExec taskExec = taskExecDAO.find(executionId);
+ if (taskExec == null) {
+ throw new NotFoundException("Task execution " + executionId);
+ }
+
+ TaskExecTO taskExecutionToDelete = binder.getTaskExecTO(taskExec);
+ taskExecDAO.delete(taskExec);
+ return taskExecutionToDelete;
+ }
+
+ @PreAuthorize("(hasRole('TASK_DELETE') and #bulkAction.operation == #bulkAction.operation.DELETE) or "
+ + "(hasRole('TASK_EXECUTE') and "
+ + "(#bulkAction.operation == #bulkAction.operation.EXECUTE or "
+ + "#bulkAction.operation == #bulkAction.operation.DRYRUN))")
+ public BulkActionResult bulk(final BulkAction bulkAction) {
+ BulkActionResult res = new BulkActionResult();
+
+ switch (bulkAction.getOperation()) {
+ case DELETE:
+ for (String taskId : bulkAction.getTargets()) {
+ try {
+ res.add(delete(Long.valueOf(taskId)).getId(), BulkActionResult.Status.SUCCESS);
+ } catch (Exception e) {
+ LOG.error("Error performing delete for task {}", taskId, e);
+ res.add(taskId, BulkActionResult.Status.FAILURE);
+ }
+ }
+ break;
+
+ case DRYRUN:
+ for (String taskId : bulkAction.getTargets()) {
+ try {
+ execute(Long.valueOf(taskId), true);
+ res.add(taskId, BulkActionResult.Status.SUCCESS);
+ } catch (Exception e) {
+ LOG.error("Error performing dryrun for task {}", taskId, e);
+ res.add(taskId, BulkActionResult.Status.FAILURE);
+ }
+ }
+ break;
+
+ case EXECUTE:
+ for (String taskId : bulkAction.getTargets()) {
+ try {
+ execute(Long.valueOf(taskId), false);
+ res.add(taskId, BulkActionResult.Status.SUCCESS);
+ } catch (Exception e) {
+ LOG.error("Error performing execute for task {}", taskId, e);
+ res.add(taskId, BulkActionResult.Status.FAILURE);
+ }
+ }
+ break;
+
+ default:
+ }
+
+ return res;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected AbstractTaskTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ Long id = null;
+
+ if (ArrayUtils.isNotEmpty(args)
+ && !"deleteExecution".equals(method.getName()) && !"readExecution".equals(method.getName())) {
+
+ for (int i = 0; id == null && i < args.length; i++) {
+ if (args[i] instanceof Long) {
+ id = (Long) args[i];
+ } else if (args[i] instanceof AbstractTaskTO) {
+ id = ((AbstractTaskTO) args[i]).getId();
+ }
+ }
+ }
+
+ if ((id != null) && !id.equals(0l)) {
+ try {
+ final Task task = taskDAO.find(id);
+ return binder.getTaskTO(task, taskUtilFactory.getInstance(task));
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UnresolvedReferenceException.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UnresolvedReferenceException.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UnresolvedReferenceException.java
new file mode 100644
index 0000000..aff28d9
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UnresolvedReferenceException.java
@@ -0,0 +1,35 @@
+/*
+ * 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.server.logic;
+
+/**
+ * Indicates unresolved bean reference.
+ */
+public class UnresolvedReferenceException extends Exception {
+
+ private static final long serialVersionUID = -675489116009955632L;
+
+ public UnresolvedReferenceException() {
+ super();
+ }
+
+ public UnresolvedReferenceException(final Throwable cause) {
+ super(cause);
+ }
+}
[05/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/AbstractReportlet.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/AbstractReportlet.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/AbstractReportlet.java
new file mode 100644
index 0000000..8c8661b
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/AbstractReportlet.java
@@ -0,0 +1,66 @@
+/*
+ * 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.server.logic.report;
+
+import org.apache.syncope.common.lib.report.AbstractReportletConf;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.transaction.annotation.Transactional;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+public abstract class AbstractReportlet<T extends AbstractReportletConf> implements Reportlet<T> {
+
+ /**
+ * Logger.
+ */
+ protected static final Logger LOG = LoggerFactory.getLogger(AbstractReportlet.class);
+
+ protected T conf;
+
+ public T getConf() {
+ return conf;
+ }
+
+ @Override
+ public void setConf(final T conf) {
+ this.conf = conf;
+ }
+
+ protected abstract void doExtract(ContentHandler handler) throws SAXException, ReportException;
+
+ @Override
+ @Transactional(readOnly = true)
+ public void extract(final ContentHandler handler) throws SAXException, ReportException {
+
+ if (conf == null) {
+ throw new ReportException(new IllegalArgumentException("No configuration provided"));
+ }
+
+ AttributesImpl atts = new AttributesImpl();
+ atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, conf.getName());
+ atts.addAttribute("", "", ReportXMLConst.ATTR_CLASS, ReportXMLConst.XSD_STRING, getClass().getName());
+ handler.startElement("", "", ReportXMLConst.ELEMENT_REPORTLET, atts);
+
+ doExtract(handler);
+
+ handler.endElement("", "", ReportXMLConst.ELEMENT_REPORTLET);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportException.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportException.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportException.java
new file mode 100644
index 0000000..b8d311b
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportException.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.server.logic.report;
+
+public class ReportException extends RuntimeException {
+
+ private static final long serialVersionUID = 6719507778589395283L;
+
+ public ReportException(final Throwable cause) {
+ super(cause);
+ }
+
+ public ReportException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportJob.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportJob.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportJob.java
new file mode 100644
index 0000000..ca59705
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportJob.java
@@ -0,0 +1,206 @@
+/*
+ * 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.server.logic.report;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Date;
+import java.util.zip.Deflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+import org.apache.commons.io.IOUtils;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.report.ReportletConf;
+import org.apache.syncope.common.lib.types.ReportExecStatus;
+import org.apache.syncope.persistence.api.dao.ReportDAO;
+import org.apache.syncope.persistence.api.dao.ReportExecDAO;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.Report;
+import org.apache.syncope.persistence.api.entity.ReportExec;
+import org.apache.syncope.server.logic.data.ReportDataBinder;
+import org.apache.syncope.server.spring.ApplicationContextProvider;
+import org.apache.syncope.server.utils.ExceptionUtil;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * Quartz job for executing a given report.
+ */
+@SuppressWarnings("unchecked")
+@DisallowConcurrentExecution
+public class ReportJob implements Job {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(ReportJob.class);
+
+ /**
+ * Report DAO.
+ */
+ @Autowired
+ private ReportDAO reportDAO;
+
+ /**
+ * Report execution DAO.
+ */
+ @Autowired
+ private ReportExecDAO reportExecDAO;
+
+ /**
+ * Report data binder.
+ */
+ @Autowired
+ private ReportDataBinder dataBinder;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ /**
+ * Key, set by the caller, for identifying the report to be executed.
+ */
+ private Long reportKey;
+
+ /**
+ * Report id setter.
+ *
+ * @param reportKey to be set
+ */
+ public void setReportKey(final Long reportKey) {
+ this.reportKey = reportKey;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public void execute(final JobExecutionContext context) throws JobExecutionException {
+ Report report = reportDAO.find(reportKey);
+ if (report == null) {
+ throw new JobExecutionException("Report " + reportKey + " not found");
+ }
+
+ // 1. create execution
+ ReportExec execution = entityFactory.newEntity(ReportExec.class);
+ execution.setStatus(ReportExecStatus.STARTED);
+ execution.setStartDate(new Date());
+ execution.setReport(report);
+ execution = reportExecDAO.save(execution);
+
+ report.addExec(execution);
+ report = reportDAO.save(report);
+
+ // 2. define a SAX handler for generating result as XML
+ TransformerHandler handler;
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ZipOutputStream zos = new ZipOutputStream(baos);
+ zos.setLevel(Deflater.BEST_COMPRESSION);
+ try {
+ SAXTransformerFactory tFactory = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
+ handler = tFactory.newTransformerHandler();
+ Transformer serializer = handler.getTransformer();
+ serializer.setOutputProperty(OutputKeys.ENCODING, SyncopeConstants.DEFAULT_ENCODING);
+ serializer.setOutputProperty(OutputKeys.INDENT, "yes");
+
+ // a single ZipEntry in the ZipOutputStream
+ zos.putNextEntry(new ZipEntry(report.getName()));
+
+ // streaming SAX handler in a compressed byte array stream
+ handler.setResult(new StreamResult(zos));
+ } catch (Exception e) {
+ throw new JobExecutionException("While configuring for SAX generation", e, true);
+ }
+
+ execution.setStatus(ReportExecStatus.RUNNING);
+ execution = reportExecDAO.save(execution);
+
+ // 3. actual report execution
+ StringBuilder reportExecutionMessage = new StringBuilder();
+ try {
+ // report header
+ handler.startDocument();
+ AttributesImpl atts = new AttributesImpl();
+ atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, report.getName());
+ handler.startElement("", "", ReportXMLConst.ELEMENT_REPORT, atts);
+
+ // iterate over reportlet instances defined for this report
+ for (ReportletConf reportletConf : report.getReportletConfs()) {
+ Class<Reportlet> reportletClass =
+ dataBinder.findReportletClassHavingConfClass(reportletConf.getClass());
+ if (reportletClass != null) {
+ Reportlet<ReportletConf> autowired =
+ (Reportlet<ReportletConf>) ApplicationContextProvider.getBeanFactory().
+ createBean(reportletClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ autowired.setConf(reportletConf);
+
+ // invoke reportlet
+ try {
+ autowired.extract(handler);
+ } catch (Exception e) {
+ execution.setStatus(ReportExecStatus.FAILURE);
+
+ Throwable t = e instanceof ReportException
+ ? e.getCause()
+ : e;
+ reportExecutionMessage.
+ append(ExceptionUtil.getFullStackTrace(t)).
+ append("\n==================\n");
+ }
+ }
+ }
+
+ // report footer
+ handler.endElement("", "", ReportXMLConst.ELEMENT_REPORT);
+ handler.endDocument();
+
+ if (!ReportExecStatus.FAILURE.name().equals(execution.getStatus())) {
+ execution.setStatus(ReportExecStatus.SUCCESS);
+ }
+ } catch (Exception e) {
+ execution.setStatus(ReportExecStatus.FAILURE);
+ reportExecutionMessage.append(ExceptionUtil.getFullStackTrace(e));
+
+ throw new JobExecutionException(e, true);
+ } finally {
+ try {
+ zos.closeEntry();
+ IOUtils.closeQuietly(zos);
+ IOUtils.closeQuietly(baos);
+ } catch (IOException e) {
+ LOG.error("While closing StreamResult's backend", e);
+ }
+
+ execution.setExecResult(baos.toByteArray());
+ execution.setMessage(reportExecutionMessage.toString());
+ execution.setEndDate(new Date());
+ reportExecDAO.save(execution);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportXMLConst.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportXMLConst.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportXMLConst.java
new file mode 100644
index 0000000..3cd22cd
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportXMLConst.java
@@ -0,0 +1,44 @@
+/*
+ * 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.server.logic.report;
+
+public final class ReportXMLConst {
+
+ public static final String XSD_STRING = "xsd:string";
+
+ public static final String XSD_INT = "xsd:integer";
+
+ public static final String XSD_LONG = "xsd:long";
+
+ public static final String XSD_BOOLEAN = "xsd:boolean";
+
+ public static final String XSD_DATETIME = "xsd:dateTime";
+
+ public static final String ELEMENT_REPORT = "report";
+
+ public static final String ATTR_NAME = "name";
+
+ public static final String ATTR_CLASS = "class";
+
+ public static final String ELEMENT_REPORTLET = "reportlet";
+
+ private ReportXMLConst() {
+ // empty private constructor for static utility class
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/Reportlet.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/Reportlet.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/Reportlet.java
new file mode 100644
index 0000000..49438bc
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/Reportlet.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.server.logic.report;
+
+import org.apache.syncope.common.lib.report.ReportletConf;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * Interface for all elements that can be embedded in a report.
+ *
+ * @see org.apache.syncope.core.persistence.beans.Report
+ */
+public interface Reportlet<T extends ReportletConf> {
+
+ /**
+ * Set this reportlet configuration.
+ *
+ * @param conf configuration
+ */
+ void setConf(T conf);
+
+ /**
+ * Actual data extraction for reporting.
+ *
+ * @param handler SAX content handler for streaming result
+ * @throws SAXException if there is any problem in SAX handling
+ * @throws ReportException if anything goes wrong
+ */
+ void extract(ContentHandler handler) throws SAXException, ReportException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportletConfClass.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportletConfClass.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportletConfClass.java
new file mode 100644
index 0000000..48896cc
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/ReportletConfClass.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.server.logic.report;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.apache.syncope.common.lib.report.ReportletConf;
+
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ReportletConfClass {
+
+ Class<? extends ReportletConf> value();
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/RoleReportlet.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/RoleReportlet.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/RoleReportlet.java
new file mode 100644
index 0000000..3ffbdfb
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/RoleReportlet.java
@@ -0,0 +1,327 @@
+/*
+ * 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.server.logic.report;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.report.RoleReportletConf;
+import org.apache.syncope.common.lib.report.RoleReportletConf.Feature;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.persistence.api.RoleEntitlementUtil;
+import org.apache.syncope.persistence.api.dao.EntitlementDAO;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.dao.SubjectSearchDAO;
+import org.apache.syncope.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.server.logic.data.RoleDataBinder;
+import org.apache.syncope.server.logic.search.SearchCondConverter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+@ReportletConfClass(RoleReportletConf.class)
+public class RoleReportlet extends AbstractReportlet<RoleReportletConf> {
+
+ private static final int PAGE_SIZE = 10;
+
+ @Autowired
+ private EntitlementDAO entitlementDAO;
+
+ @Autowired
+ private RoleDAO roleDAO;
+
+ @Autowired
+ private SubjectSearchDAO searchDAO;
+
+ @Autowired
+ private RoleDataBinder roleDataBinder;
+
+ private List<Role> getPagedRoles(final int page) {
+ final Set<Long> adminRoleIds = RoleEntitlementUtil.getRoleKeys(entitlementDAO.findAll());
+ final List<Role> result;
+ if (StringUtils.isBlank(conf.getMatchingCond())) {
+ result = roleDAO.findAll();
+ } else {
+ result = searchDAO.search(adminRoleIds, SearchCondConverter.convert(conf.getMatchingCond()),
+ page, PAGE_SIZE, Collections.<OrderByClause>emptyList(), SubjectType.ROLE);
+ }
+
+ return result;
+ }
+
+ private int count() {
+ Set<Long> adminRoleIds = RoleEntitlementUtil.getRoleKeys(entitlementDAO.findAll());
+
+ return StringUtils.isBlank(conf.getMatchingCond())
+ ? roleDAO.findAll().size()
+ : searchDAO.count(adminRoleIds, SearchCondConverter.convert(conf.getMatchingCond()), SubjectType.ROLE);
+ }
+
+ private void doExtractResources(final ContentHandler handler, final AbstractSubjectTO subjectTO)
+ throws SAXException {
+
+ if (subjectTO.getResources().isEmpty()) {
+ LOG.debug("No resources found for {}[{}]", subjectTO.getClass().getSimpleName(), subjectTO.getKey());
+ } else {
+ AttributesImpl atts = new AttributesImpl();
+ handler.startElement("", "", "resources", null);
+
+ for (String resourceName : subjectTO.getResources()) {
+ atts.clear();
+
+ atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, resourceName);
+ handler.startElement("", "", "resource", atts);
+ handler.endElement("", "", "resource");
+ }
+
+ handler.endElement("", "", "resources");
+ }
+ }
+
+ private void doExtractAttributes(final ContentHandler handler, final AbstractAttributableTO attributableTO,
+ final Collection<String> attrs, final Collection<String> derAttrs, final Collection<String> virAttrs)
+ throws SAXException {
+
+ AttributesImpl atts = new AttributesImpl();
+ if (!attrs.isEmpty()) {
+ Map<String, AttrTO> attrMap = attributableTO.getAttrMap();
+
+ handler.startElement("", "", "attributes", null);
+ for (String attrName : attrs) {
+ atts.clear();
+
+ atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, attrName);
+ handler.startElement("", "", "attribute", atts);
+
+ if (attrMap.containsKey(attrName)) {
+ for (String value : attrMap.get(attrName).getValues()) {
+ handler.startElement("", "", "value", null);
+ handler.characters(value.toCharArray(), 0, value.length());
+ handler.endElement("", "", "value");
+ }
+ } else {
+ LOG.debug("{} not found for {}[{}]", attrName,
+ attributableTO.getClass().getSimpleName(), attributableTO.getKey());
+ }
+
+ handler.endElement("", "", "attribute");
+ }
+ handler.endElement("", "", "attributes");
+ }
+
+ if (!derAttrs.isEmpty()) {
+ Map<String, AttrTO> derAttrMap = attributableTO.getDerAttrMap();
+
+ handler.startElement("", "", "derivedAttributes", null);
+ for (String attrName : derAttrs) {
+ atts.clear();
+
+ atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, attrName);
+ handler.startElement("", "", "derivedAttribute", atts);
+
+ if (derAttrMap.containsKey(attrName)) {
+ for (String value : derAttrMap.get(attrName).getValues()) {
+ handler.startElement("", "", "value", null);
+ handler.characters(value.toCharArray(), 0, value.length());
+ handler.endElement("", "", "value");
+ }
+ } else {
+ LOG.debug("{} not found for {}[{}]", attrName,
+ attributableTO.getClass().getSimpleName(), attributableTO.getKey());
+ }
+
+ handler.endElement("", "", "derivedAttribute");
+ }
+ handler.endElement("", "", "derivedAttributes");
+ }
+
+ if (!virAttrs.isEmpty()) {
+ Map<String, AttrTO> virAttrMap = attributableTO.getVirAttrMap();
+
+ handler.startElement("", "", "virtualAttributes", null);
+ for (String attrName : virAttrs) {
+ atts.clear();
+
+ atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, attrName);
+ handler.startElement("", "", "virtualAttribute", atts);
+
+ if (virAttrMap.containsKey(attrName)) {
+ for (String value : virAttrMap.get(attrName).getValues()) {
+ handler.startElement("", "", "value", null);
+ handler.characters(value.toCharArray(), 0, value.length());
+ handler.endElement("", "", "value");
+ }
+ } else {
+ LOG.debug("{} not found for {}[{}]", attrName,
+ attributableTO.getClass().getSimpleName(), attributableTO.getKey());
+ }
+
+ handler.endElement("", "", "virtualAttribute");
+ }
+ handler.endElement("", "", "virtualAttributes");
+ }
+ }
+
+ private void doExtract(final ContentHandler handler, final List<Role> roles)
+ throws SAXException, ReportException {
+
+ AttributesImpl atts = new AttributesImpl();
+ for (Role role : roles) {
+ atts.clear();
+
+ for (Feature feature : conf.getFeatures()) {
+ String type = null;
+ String value = null;
+ switch (feature) {
+ case key:
+ type = ReportXMLConst.XSD_LONG;
+ value = String.valueOf(role.getKey());
+ break;
+
+ case name:
+ type = ReportXMLConst.XSD_STRING;
+ value = String.valueOf(role.getName());
+ break;
+
+ case roleOwner:
+ type = ReportXMLConst.XSD_LONG;
+ value = String.valueOf(role.getRoleOwner());
+ break;
+
+ case userOwner:
+ type = ReportXMLConst.XSD_LONG;
+ value = String.valueOf(role.getUserOwner());
+ break;
+
+ default:
+ }
+
+ if (type != null && value != null) {
+ atts.addAttribute("", "", feature.name(), type, value);
+ }
+ }
+
+ handler.startElement("", "", "role", atts);
+
+ // Using RoleTO for attribute values, since the conversion logic of
+ // values to String is already encapsulated there
+ RoleTO roleTO = roleDataBinder.getRoleTO(role);
+
+ doExtractAttributes(handler, roleTO, conf.getAttrs(), conf.getDerAttrs(), conf.getVirAttrs());
+
+ if (conf.getFeatures().contains(Feature.entitlements)) {
+ handler.startElement("", "", "entitlements", null);
+
+ for (String ent : roleTO.getEntitlements()) {
+ atts.clear();
+
+ atts.addAttribute("", "", "id", ReportXMLConst.XSD_STRING, String.valueOf(ent));
+
+ handler.startElement("", "", "entitlement", atts);
+ handler.endElement("", "", "entitlement");
+ }
+
+ handler.endElement("", "", "entitlements");
+ }
+ // to get resources associated to a role
+ if (conf.getFeatures().contains(Feature.resources)) {
+ doExtractResources(handler, roleTO);
+ }
+ //to get users asscoiated to a role is preferred RoleDAO to RoleTO
+ if (conf.getFeatures().contains(Feature.users)) {
+ handler.startElement("", "", "users", null);
+
+ for (Membership memb : roleDAO.findMemberships(role)) {
+ atts.clear();
+
+ atts.addAttribute("", "", "key", ReportXMLConst.XSD_LONG,
+ String.valueOf(memb.getUser().getKey()));
+ atts.addAttribute("", "", "username", ReportXMLConst.XSD_STRING,
+ String.valueOf(memb.getUser().getUsername()));
+
+ handler.startElement("", "", "user", atts);
+ handler.endElement("", "", "user");
+ }
+
+ handler.endElement("", "", "users");
+ }
+
+ handler.endElement("", "", "role");
+ }
+ }
+
+ private void doExtractConf(final ContentHandler handler) throws SAXException {
+ if (conf == null) {
+ LOG.debug("Report configuration is not present");
+ }
+
+ AttributesImpl atts = new AttributesImpl();
+ handler.startElement("", "", "configurations", null);
+ handler.startElement("", "", "roleAttributes", atts);
+
+ for (Feature feature : conf.getFeatures()) {
+ atts.clear();
+ handler.startElement("", "", "feature", atts);
+ handler.characters(feature.name().toCharArray(), 0, feature.name().length());
+ handler.endElement("", "", "feature");
+ }
+
+ for (String attr : conf.getAttrs()) {
+ atts.clear();
+ handler.startElement("", "", "attribute", atts);
+ handler.characters(attr.toCharArray(), 0, attr.length());
+ handler.endElement("", "", "attribute");
+ }
+
+ for (String derAttr : conf.getDerAttrs()) {
+ atts.clear();
+ handler.startElement("", "", "derAttribute", atts);
+ handler.characters(derAttr.toCharArray(), 0, derAttr.length());
+ handler.endElement("", "", "derAttribute");
+ }
+
+ for (String virAttr : conf.getVirAttrs()) {
+ atts.clear();
+ handler.startElement("", "", "virAttribute", atts);
+ handler.characters(virAttr.toCharArray(), 0, virAttr.length());
+ handler.endElement("", "", "virAttribute");
+ }
+
+ handler.endElement("", "", "roleAttributes");
+ handler.endElement("", "", "configurations");
+ }
+
+ @Override
+ protected void doExtract(final ContentHandler handler) throws SAXException, ReportException {
+ doExtractConf(handler);
+ for (int i = 1; i <= (count() / PAGE_SIZE) + 1; i++) {
+ doExtract(handler, getPagedRoles(i));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/StaticReportlet.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/StaticReportlet.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/StaticReportlet.java
new file mode 100644
index 0000000..bdc76f8
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/StaticReportlet.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.server.logic.report;
+
+import org.apache.syncope.common.lib.report.StaticReportletConf;
+import org.apache.syncope.server.utils.DataFormat;
+import org.springframework.util.StringUtils;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+@ReportletConfClass(StaticReportletConf.class)
+public class StaticReportlet extends AbstractReportlet<StaticReportletConf> {
+
+ private void doExtractConf(final ContentHandler handler) throws SAXException {
+
+ AttributesImpl atts = new AttributesImpl();
+ handler.startElement("", "", "configurations", null);
+ handler.startElement("", "", "staticAttributes", atts);
+
+ handler.startElement("", "", "string", atts);
+ handler.characters("string".toCharArray(), 0, "string".length());
+ handler.endElement("", "", "string");
+
+ handler.startElement("", "", "long", atts);
+ handler.characters("long".toCharArray(), 0, "long".length());
+ handler.endElement("", "", "long");
+
+ handler.startElement("", "", "double", atts);
+ handler.characters("double".toCharArray(), 0, "double".length());
+ handler.endElement("", "", "double");
+
+ handler.startElement("", "", "date", atts);
+ handler.characters("date".toCharArray(), 0, "date".length());
+ handler.endElement("", "", "date");
+
+ handler.startElement("", "", "double", atts);
+ handler.characters("double".toCharArray(), 0, "double".length());
+ handler.endElement("", "", "double");
+
+ handler.startElement("", "", "enum", atts);
+ handler.characters("enum".toCharArray(), 0, "enum".length());
+ handler.endElement("", "", "enum");
+
+ handler.startElement("", "", "list", atts);
+ handler.characters("list".toCharArray(), 0, "list".length());
+ handler.endElement("", "", "list");
+
+ handler.endElement("", "", "staticAttributes");
+ handler.endElement("", "", "configurations");
+ }
+
+ @Override
+ public void doExtract(final ContentHandler handler) throws SAXException, ReportException {
+
+ doExtractConf(handler);
+
+ if (StringUtils.hasText(conf.getStringField())) {
+ handler.startElement("", "", "string", null);
+ handler.characters(conf.getStringField().toCharArray(), 0, conf.getStringField().length());
+ handler.endElement("", "", "string");
+ }
+
+ if (conf.getLongField() != null) {
+ handler.startElement("", "", "long", null);
+ String printed = String.valueOf(conf.getLongField());
+ handler.characters(printed.toCharArray(), 0, printed.length());
+ handler.endElement("", "", "long");
+ }
+
+ if (conf.getDoubleField() != null) {
+ handler.startElement("", "", "double", null);
+ String printed = String.valueOf(conf.getDoubleField());
+ handler.characters(printed.toCharArray(), 0, printed.length());
+ handler.endElement("", "", "double");
+ }
+
+ if (conf.getDateField() != null) {
+ handler.startElement("", "", "date", null);
+ String printed = DataFormat.format(conf.getDateField());
+ handler.characters(printed.toCharArray(), 0, printed.length());
+ handler.endElement("", "", "date");
+ }
+
+ if (conf.getTraceLevel() != null) {
+ handler.startElement("", "", "enum", null);
+ String printed = conf.getTraceLevel().name();
+ handler.characters(printed.toCharArray(), 0, printed.length());
+ handler.endElement("", "", "enum");
+ }
+
+ if (conf.getListField() != null && !conf.getListField().isEmpty()) {
+ handler.startElement("", "", "list", null);
+ for (String item : conf.getListField()) {
+ if (StringUtils.hasText(item)) {
+ handler.startElement("", "", "string", null);
+ handler.characters(item.toCharArray(), 0, item.length());
+ handler.endElement("", "", "string");
+ }
+ }
+ handler.endElement("", "", "list");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/TextSerializer.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/TextSerializer.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/TextSerializer.java
new file mode 100644
index 0000000..8ad63fc
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/TextSerializer.java
@@ -0,0 +1,101 @@
+/*
+ * 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.server.logic.report;
+
+import org.apache.cocoon.sax.component.XMLSerializer;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+/**
+ * Converts XML into plain text. It omits all XML tags and writes only character events to the output. Input document
+ * must have at least one element - root element - which should wrap all the text inside it.
+ *
+ */
+public class TextSerializer extends XMLSerializer {
+
+ private static final String UTF_8 = "UTF-8";
+
+ private static final String TXT = "text";
+
+ public TextSerializer() {
+ super();
+ super.setOmitXmlDeclaration(true);
+ }
+
+ @Override
+ public void setDocumentLocator(final Locator locator) {
+ // nothing
+ }
+
+ @Override
+ public void processingInstruction(final String target, final String data)
+ throws SAXException {
+ // nothing
+ }
+
+ @Override
+ public void startDTD(final String name, final String publicId, final String systemId)
+ throws SAXException {
+ // nothing
+ }
+
+ @Override
+ public void endDTD() throws SAXException {
+ // nothing
+ }
+
+ @Override
+ public void startElement(final String uri, final String loc, final String raw, final Attributes atts)
+ throws SAXException {
+ // nothing
+ }
+
+ @Override
+ public void endElement(final String uri, final String name, final String raw)
+ throws SAXException {
+ // nothing
+ }
+
+ @Override
+ public void endDocument() throws SAXException {
+ super.endDocument();
+ }
+
+ /**
+ * @throws SAXException if text is encountered before root element.
+ */
+ @Override
+ public void characters(final char buffer[], final int start, final int len) throws SAXException {
+ super.characters(buffer, start, len);
+ }
+
+ @Override
+ public void recycle() {
+ super.recycle();
+ }
+
+ public static TextSerializer createPlainSerializer() {
+ final TextSerializer serializer = new TextSerializer();
+ serializer.setContentType("text/plain; charset=" + UTF_8);
+ serializer.setEncoding(UTF_8);
+ serializer.setMethod(TXT);
+ return serializer;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/UserReportlet.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/UserReportlet.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/UserReportlet.java
new file mode 100644
index 0000000..ecae604
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/report/UserReportlet.java
@@ -0,0 +1,359 @@
+/*
+ * 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.server.logic.report;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.report.UserReportletConf;
+import org.apache.syncope.common.lib.report.UserReportletConf.Feature;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.persistence.api.RoleEntitlementUtil;
+import org.apache.syncope.persistence.api.dao.EntitlementDAO;
+import org.apache.syncope.persistence.api.dao.SubjectSearchDAO;
+import org.apache.syncope.persistence.api.dao.UserDAO;
+import org.apache.syncope.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.server.logic.data.RoleDataBinder;
+import org.apache.syncope.server.logic.data.UserDataBinder;
+import org.apache.syncope.server.logic.search.SearchCondConverter;
+import org.apache.syncope.server.utils.DataFormat;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+@ReportletConfClass(UserReportletConf.class)
+public class UserReportlet extends AbstractReportlet<UserReportletConf> {
+
+ private static final int PAGE_SIZE = 10;
+
+ @Autowired
+ private EntitlementDAO entitlementDAO;
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private SubjectSearchDAO searchDAO;
+
+ @Autowired
+ private UserDataBinder userDataBinder;
+
+ @Autowired
+ private RoleDataBinder roleDataBinder;
+
+ private List<User> getPagedUsers(final int page) {
+ final Set<Long> adminRoleIds = RoleEntitlementUtil.getRoleKeys(entitlementDAO.findAll());
+
+ final List<User> result;
+ if (StringUtils.isBlank(conf.getMatchingCond())) {
+ result = userDAO.findAll(adminRoleIds, page, PAGE_SIZE);
+ } else {
+ result = searchDAO.search(adminRoleIds, SearchCondConverter.convert(conf.getMatchingCond()),
+ page, PAGE_SIZE, Collections.<OrderByClause>emptyList(), SubjectType.USER);
+ }
+
+ return result;
+ }
+
+ private int count() {
+ Set<Long> adminRoleIds = RoleEntitlementUtil.getRoleKeys(entitlementDAO.findAll());
+
+ return StringUtils.isBlank(conf.getMatchingCond())
+ ? userDAO.count(adminRoleIds)
+ : searchDAO.count(adminRoleIds, SearchCondConverter.convert(conf.getMatchingCond()), SubjectType.USER);
+ }
+
+ private void doExtractResources(final ContentHandler handler, final AbstractSubjectTO subjectTO)
+ throws SAXException {
+
+ if (subjectTO.getResources().isEmpty()) {
+ LOG.debug("No resources found for {}[{}]", subjectTO.getClass().getSimpleName(), subjectTO.getKey());
+ } else {
+ AttributesImpl atts = new AttributesImpl();
+ handler.startElement("", "", "resources", null);
+
+ for (String resourceName : subjectTO.getResources()) {
+ atts.clear();
+
+ atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, resourceName);
+ handler.startElement("", "", "resource", atts);
+ handler.endElement("", "", "resource");
+ }
+
+ handler.endElement("", "", "resources");
+ }
+ }
+
+ private void doExtractAttributes(final ContentHandler handler, final AbstractAttributableTO attributableTO,
+ final Collection<String> attrs, final Collection<String> derAttrs, final Collection<String> virAttrs)
+ throws SAXException {
+
+ AttributesImpl atts = new AttributesImpl();
+ if (!attrs.isEmpty()) {
+ Map<String, AttrTO> attrMap = attributableTO.getAttrMap();
+
+ handler.startElement("", "", "attributes", null);
+ for (String attrName : attrs) {
+ atts.clear();
+
+ atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, attrName);
+ handler.startElement("", "", "attribute", atts);
+
+ if (attrMap.containsKey(attrName)) {
+ for (String value : attrMap.get(attrName).getValues()) {
+ handler.startElement("", "", "value", null);
+ handler.characters(value.toCharArray(), 0, value.length());
+ handler.endElement("", "", "value");
+ }
+ } else {
+ LOG.debug("{} not found for {}[{}]", attrName,
+ attributableTO.getClass().getSimpleName(), attributableTO.getKey());
+ }
+
+ handler.endElement("", "", "attribute");
+ }
+ handler.endElement("", "", "attributes");
+ }
+
+ if (!derAttrs.isEmpty()) {
+ Map<String, AttrTO> derAttrMap = attributableTO.getDerAttrMap();
+
+ handler.startElement("", "", "derivedAttributes", null);
+ for (String attrName : derAttrs) {
+ atts.clear();
+
+ atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, attrName);
+ handler.startElement("", "", "derivedAttribute", atts);
+
+ if (derAttrMap.containsKey(attrName)) {
+ for (String value : derAttrMap.get(attrName).getValues()) {
+ handler.startElement("", "", "value", null);
+ handler.characters(value.toCharArray(), 0, value.length());
+ handler.endElement("", "", "value");
+ }
+ } else {
+ LOG.debug("{} not found for {}[{}]", attrName,
+ attributableTO.getClass().getSimpleName(), attributableTO.getKey());
+ }
+
+ handler.endElement("", "", "derivedAttribute");
+ }
+ handler.endElement("", "", "derivedAttributes");
+ }
+
+ if (!virAttrs.isEmpty()) {
+ Map<String, AttrTO> virAttrMap = attributableTO.getVirAttrMap();
+
+ handler.startElement("", "", "virtualAttributes", null);
+ for (String attrName : virAttrs) {
+ atts.clear();
+
+ atts.addAttribute("", "", ReportXMLConst.ATTR_NAME, ReportXMLConst.XSD_STRING, attrName);
+ handler.startElement("", "", "virtualAttribute", atts);
+
+ if (virAttrMap.containsKey(attrName)) {
+ for (String value : virAttrMap.get(attrName).getValues()) {
+ handler.startElement("", "", "value", null);
+ handler.characters(value.toCharArray(), 0, value.length());
+ handler.endElement("", "", "value");
+ }
+ } else {
+ LOG.debug("{} not found for {}[{}]", attrName,
+ attributableTO.getClass().getSimpleName(), attributableTO.getKey());
+ }
+
+ handler.endElement("", "", "virtualAttribute");
+ }
+ handler.endElement("", "", "virtualAttributes");
+ }
+ }
+
+ private void doExtract(final ContentHandler handler, final List<User> users)
+ throws SAXException, ReportException {
+
+ AttributesImpl atts = new AttributesImpl();
+ for (User user : users) {
+ atts.clear();
+
+ for (Feature feature : conf.getFeatures()) {
+ String type = null;
+ String value = null;
+ switch (feature) {
+ case key:
+ type = ReportXMLConst.XSD_LONG;
+ value = String.valueOf(user.getKey());
+ break;
+
+ case username:
+ type = ReportXMLConst.XSD_STRING;
+ value = user.getUsername();
+ break;
+
+ case workflowId:
+ type = ReportXMLConst.XSD_LONG;
+ value = String.valueOf(user.getWorkflowId());
+ break;
+
+ case status:
+ type = ReportXMLConst.XSD_STRING;
+ value = user.getStatus();
+ break;
+
+ case creationDate:
+ type = ReportXMLConst.XSD_DATETIME;
+ value = user.getCreationDate() == null
+ ? ""
+ : DataFormat.format(user.getCreationDate());
+ break;
+
+ case lastLoginDate:
+ type = ReportXMLConst.XSD_DATETIME;
+ value = user.getLastLoginDate() == null
+ ? ""
+ : DataFormat.format(user.getLastLoginDate());
+ break;
+
+ case changePwdDate:
+ type = ReportXMLConst.XSD_DATETIME;
+ value = user.getChangePwdDate() == null
+ ? ""
+ : DataFormat.format(user.getChangePwdDate());
+ break;
+
+ case passwordHistorySize:
+ type = ReportXMLConst.XSD_INT;
+ value = String.valueOf(user.getPasswordHistory().size());
+ break;
+
+ case failedLoginCount:
+ type = ReportXMLConst.XSD_INT;
+ value = String.valueOf(user.getFailedLogins());
+ break;
+
+ default:
+ }
+
+ if (type != null && value != null) {
+ atts.addAttribute("", "", feature.name(), type, value);
+ }
+ }
+
+ handler.startElement("", "", "user", atts);
+
+ // Using UserTO for attribute values, since the conversion logic of
+ // values to String is already encapsulated there
+ UserTO userTO = userDataBinder.getUserTO(user);
+
+ doExtractAttributes(handler, userTO, conf.getAttrs(), conf.getDerAttrs(), conf.getVirAttrs());
+
+ if (conf.getFeatures().contains(Feature.memberships)) {
+ handler.startElement("", "", "memberships", null);
+
+ for (MembershipTO memb : userTO.getMemberships()) {
+ atts.clear();
+
+ atts.addAttribute("", "", "id", ReportXMLConst.XSD_LONG, String.valueOf(memb.getKey()));
+ atts.addAttribute("", "", "roleId", ReportXMLConst.XSD_LONG, String.valueOf(memb.getRoleId()));
+ atts.addAttribute("", "", "roleName", ReportXMLConst.XSD_STRING, String.valueOf(memb.getRoleName()));
+ handler.startElement("", "", "membership", atts);
+
+ doExtractAttributes(handler, memb, memb.getAttrMap().keySet(), memb.getDerAttrMap()
+ .keySet(), memb.getVirAttrMap().keySet());
+
+ if (conf.getFeatures().contains(Feature.resources)) {
+ Membership actualMemb = user.getMembership(memb.getRoleId());
+ if (actualMemb == null) {
+ LOG.warn("Unexpected: cannot find membership for role {} for user {}", memb.getRoleId(),
+ user);
+ } else {
+ doExtractResources(handler, roleDataBinder.getRoleTO(actualMemb.getRole()));
+ }
+ }
+
+ handler.endElement("", "", "membership");
+ }
+
+ handler.endElement("", "", "memberships");
+ }
+
+ if (conf.getFeatures().contains(Feature.resources)) {
+ doExtractResources(handler, userTO);
+ }
+
+ handler.endElement("", "", "user");
+ }
+ }
+
+ private void doExtractConf(final ContentHandler handler) throws SAXException {
+
+ AttributesImpl atts = new AttributesImpl();
+ handler.startElement("", "", "configurations", null);
+ handler.startElement("", "", "userAttributes", atts);
+
+ for (Feature feature : conf.getFeatures()) {
+ atts.clear();
+ handler.startElement("", "", "feature", atts);
+ handler.characters(feature.name().toCharArray(), 0, feature.name().length());
+ handler.endElement("", "", "feature");
+ }
+
+ for (String attr : conf.getAttrs()) {
+ atts.clear();
+ handler.startElement("", "", "attribute", atts);
+ handler.characters(attr.toCharArray(), 0, attr.length());
+ handler.endElement("", "", "attribute");
+ }
+
+ for (String derAttr : conf.getDerAttrs()) {
+ atts.clear();
+ handler.startElement("", "", "derAttribute", atts);
+ handler.characters(derAttr.toCharArray(), 0, derAttr.length());
+ handler.endElement("", "", "derAttribute");
+ }
+
+ for (String virAttr : conf.getVirAttrs()) {
+ atts.clear();
+ handler.startElement("", "", "virAttribute", atts);
+ handler.characters(virAttr.toCharArray(), 0, virAttr.length());
+ handler.endElement("", "", "virAttribute");
+ }
+
+ handler.endElement("", "", "userAttributes");
+ handler.endElement("", "", "configurations");
+ }
+
+ @Override
+ protected void doExtract(final ContentHandler handler) throws SAXException, ReportException {
+ doExtractConf(handler);
+ for (int i = 1; i <= (count() / PAGE_SIZE) + 1; i++) {
+ doExtract(handler, getPagedUsers(i));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/search/SearchCondConverter.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/search/SearchCondConverter.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/search/SearchCondConverter.java
new file mode 100644
index 0000000..662cd46
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/search/SearchCondConverter.java
@@ -0,0 +1,50 @@
+/*
+ * 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.server.logic.search;
+
+import org.apache.cxf.jaxrs.ext.search.SearchBean;
+import org.apache.cxf.jaxrs.ext.search.fiql.FiqlParser;
+import org.apache.syncope.common.lib.search.SyncopeFiqlSearchConditionBuilder;
+import org.apache.syncope.persistence.api.dao.search.SearchCond;
+
+/**
+ * Converts FIQL expressions to Syncope's <tt>SearchCond</tt>.
+ */
+public final class SearchCondConverter {
+
+ /**
+ * Parses a FIQL expression into Syncope's <tt>SearchCond</tt>, using CXF's <tt>FiqlParser</tt>.
+ *
+ * @param fiqlExpression FIQL string
+ * @return <tt>SearchCond</tt> instance for given FIQL expression
+ * @see FiqlParser
+ */
+ public static SearchCond convert(final String fiqlExpression) {
+ FiqlParser<SearchBean> fiqlParser = new FiqlParser<SearchBean>(
+ SearchBean.class, SyncopeFiqlSearchConditionBuilder.CONTEXTUAL_PROPERTIES);
+ SearchCondVisitor searchCondVisitor = new SearchCondVisitor();
+
+ searchCondVisitor.visit(fiqlParser.parse(fiqlExpression));
+ return searchCondVisitor.getQuery();
+ }
+
+ private SearchCondConverter() {
+ // empty constructor for static utility class
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/search/SearchCondVisitor.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/search/SearchCondVisitor.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/search/SearchCondVisitor.java
new file mode 100644
index 0000000..5c9acdb
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/search/SearchCondVisitor.java
@@ -0,0 +1,203 @@
+/*
+ * 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.server.logic.search;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.cxf.jaxrs.ext.search.ConditionType;
+import org.apache.cxf.jaxrs.ext.search.SearchBean;
+import org.apache.cxf.jaxrs.ext.search.SearchCondition;
+import org.apache.cxf.jaxrs.ext.search.SearchUtils;
+import org.apache.cxf.jaxrs.ext.search.visitor.AbstractSearchConditionVisitor;
+import org.apache.syncope.common.lib.search.SearchableFields;
+import org.apache.syncope.common.lib.search.SpecialAttr;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.persistence.api.dao.search.AttributeCond;
+import org.apache.syncope.persistence.api.dao.search.EntitlementCond;
+import org.apache.syncope.persistence.api.dao.search.MembershipCond;
+import org.apache.syncope.persistence.api.dao.search.ResourceCond;
+import org.apache.syncope.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.persistence.api.dao.search.SubjectCond;
+
+/**
+ * Converts CXF's <tt>SearchCondition</tt> into internal <tt>SearchCond</tt>.
+ */
+public class SearchCondVisitor extends AbstractSearchConditionVisitor<SearchBean, SearchCond> {
+
+ private static final List<String> ATTRIBUTABLE_FIELDS;
+
+ static {
+ ATTRIBUTABLE_FIELDS = new ArrayList<String>();
+ ATTRIBUTABLE_FIELDS.addAll(SearchableFields.get(UserTO.class));
+ ATTRIBUTABLE_FIELDS.addAll(SearchableFields.get(RoleTO.class));
+ }
+
+ private SearchCond searchCond;
+
+ public SearchCondVisitor() {
+ super(null);
+ }
+
+ public SearchCondVisitor(final Map<String, String> fieldMap) {
+ super(fieldMap);
+ }
+
+ private AttributeCond createAttributeCond(final String schema) {
+ AttributeCond attributeCond = ATTRIBUTABLE_FIELDS.contains(schema)
+ ? new SubjectCond()
+ : new AttributeCond();
+ attributeCond.setSchema(schema);
+ return attributeCond;
+ }
+
+ private SearchCond visitPrimitive(final SearchCondition<SearchBean> sc) {
+ String name = getRealPropertyName(sc.getStatement().getProperty());
+ SpecialAttr specialAttrName = SpecialAttr.fromString(name);
+
+ String value = SearchUtils.toSqlWildcardString(sc.getStatement().getValue().toString(), false).
+ replaceAll("\\\\_", "_");
+ SpecialAttr specialAttrValue = SpecialAttr.fromString(value);
+
+ AttributeCond attributeCond = createAttributeCond(name);
+ attributeCond.setExpression(value);
+
+ SearchCond leaf;
+ switch (sc.getConditionType()) {
+ case EQUALS:
+ case NOT_EQUALS:
+ if (specialAttrName == null) {
+ if (specialAttrValue != null && specialAttrValue == SpecialAttr.NULL) {
+ attributeCond.setType(AttributeCond.Type.ISNULL);
+ attributeCond.setExpression(null);
+ } else if (value.indexOf('%') == -1) {
+ attributeCond.setType(AttributeCond.Type.EQ);
+ } else {
+ attributeCond.setType(AttributeCond.Type.LIKE);
+ }
+
+ leaf = SearchCond.getLeafCond(attributeCond);
+ } else {
+ switch (specialAttrName) {
+ case ROLES:
+ MembershipCond membershipCond = new MembershipCond();
+ membershipCond.setRoleId(Long.valueOf(value));
+ leaf = SearchCond.getLeafCond(membershipCond);
+ break;
+
+ case RESOURCES:
+ ResourceCond resourceCond = new ResourceCond();
+ resourceCond.setResourceName(value);
+ leaf = SearchCond.getLeafCond(resourceCond);
+ break;
+
+ case ENTITLEMENTS:
+ EntitlementCond entitlementCond = new EntitlementCond();
+ entitlementCond.setExpression(value);
+ leaf = SearchCond.getLeafCond(entitlementCond);
+ break;
+
+ default:
+ throw new IllegalArgumentException(
+ String.format("Special attr name %s is not supported", specialAttrName));
+ }
+ }
+ if (sc.getConditionType() == ConditionType.NOT_EQUALS) {
+ if (leaf.getAttributeCond() != null
+ && leaf.getAttributeCond().getType() == AttributeCond.Type.ISNULL) {
+
+ leaf.getAttributeCond().setType(AttributeCond.Type.ISNOTNULL);
+ } else if (leaf.getSubjectCond() != null
+ && leaf.getSubjectCond().getType() == SubjectCond.Type.ISNULL) {
+
+ leaf.getSubjectCond().setType(AttributeCond.Type.ISNOTNULL);
+ } else {
+ leaf = SearchCond.getNotLeafCond(leaf);
+ }
+ }
+ break;
+
+ case GREATER_OR_EQUALS:
+ attributeCond.setType(AttributeCond.Type.GE);
+ leaf = SearchCond.getLeafCond(attributeCond);
+ break;
+
+ case GREATER_THAN:
+ attributeCond.setType(AttributeCond.Type.GT);
+ leaf = SearchCond.getLeafCond(attributeCond);
+ break;
+
+ case LESS_OR_EQUALS:
+ attributeCond.setType(AttributeCond.Type.LE);
+ leaf = SearchCond.getLeafCond(attributeCond);
+ break;
+
+ case LESS_THAN:
+ attributeCond.setType(AttributeCond.Type.LT);
+ leaf = SearchCond.getLeafCond(attributeCond);
+ break;
+
+ default:
+ throw new IllegalArgumentException(
+ String.format("Condition type %s is not supported", sc.getConditionType().name()));
+ }
+
+ return leaf;
+ }
+
+ private SearchCond visitCompount(final SearchCondition<SearchBean> sc) {
+ List<SearchCond> searchConds = new ArrayList<SearchCond>();
+ for (SearchCondition<SearchBean> searchCondition : sc.getSearchConditions()) {
+ searchConds.add(searchCondition.getStatement() == null
+ ? visitCompount(searchCondition)
+ : visitPrimitive(searchCondition));
+ }
+
+ SearchCond compound;
+ switch (sc.getConditionType()) {
+ case AND:
+ compound = SearchCond.getAndCond(searchConds);
+ break;
+
+ case OR:
+ compound = SearchCond.getOrCond(searchConds);
+ break;
+
+ default:
+ throw new IllegalArgumentException(
+ String.format("Condition type %s is not supported", sc.getConditionType().name()));
+ }
+
+ return compound;
+ }
+
+ @Override
+ public void visit(final SearchCondition<SearchBean> sc) {
+ searchCond = sc.getStatement() == null
+ ? visitCompount(sc)
+ : visitPrimitive(sc);
+ }
+
+ @Override
+ public SearchCond getQuery() {
+ return searchCond;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/DuplicateException.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/DuplicateException.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/DuplicateException.java
new file mode 100644
index 0000000..517d64d
--- /dev/null
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/DuplicateException.java
@@ -0,0 +1,35 @@
+/*
+ * 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.persistence.api.dao;
+
+/**
+ * Thrown when something is not found.
+ */
+public class DuplicateException extends RuntimeException {
+
+ private static final long serialVersionUID = -8200698688516957508L;
+
+ public DuplicateException(final String msg) {
+ super(msg);
+ }
+
+ public DuplicateException(final String msg, final Exception cause) {
+ super(msg, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/RoleDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/RoleDAO.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/RoleDAO.java
index b2d7dd3..d26615d 100644
--- a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/RoleDAO.java
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/RoleDAO.java
@@ -77,4 +77,6 @@ public interface RoleDAO extends SubjectDAO<RPlainAttr, RDerAttr, RVirAttr> {
void delete(Role role);
void delete(Long key);
+
+ Role authFetchRole(Long key);
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/UserDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/UserDAO.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/UserDAO.java
index 42ea10a..0f359c3 100644
--- a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/UserDAO.java
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/dao/UserDAO.java
@@ -62,4 +62,7 @@ public interface UserDAO extends SubjectDAO<UPlainAttr, UDerAttr, UVirAttr> {
void delete(User user);
+ User authFecthUser(Long key);
+
+ User authFecthUser(String username);
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/AttributableUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/AttributableUtil.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/AttributableUtil.java
index ff1679c..3d12ec9 100644
--- a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/AttributableUtil.java
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/AttributableUtil.java
@@ -19,6 +19,8 @@
package org.apache.syncope.persistence.api.entity;
import java.util.List;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
import org.apache.syncope.common.lib.types.AttributableType;
import org.apache.syncope.common.lib.types.IntMappingType;
import org.apache.syncope.common.lib.types.MappingPurpose;
@@ -83,4 +85,7 @@ public interface AttributableUtil {
<T extends MappingItem> Class<T> mappingItemClass();
+ <T extends AbstractAttributableTO> T newAttributableTO();
+
+ <T extends AbstractSubjectTO> T newSubjectTO();
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/AttributableUtilFactory.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/AttributableUtilFactory.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/AttributableUtilFactory.java
new file mode 100644
index 0000000..1f42c17
--- /dev/null
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/AttributableUtilFactory.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.persistence.api.entity;
+
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.identityconnectors.framework.common.objects.ObjectClass;
+
+public interface AttributableUtilFactory {
+
+ AttributableUtil getInstance(AttributableType type);
+
+ AttributableUtil getInstance(String attributableType);
+
+ AttributableUtil getInstance(ObjectClass objectClass);
+
+ AttributableUtil getInstance(Attributable<?, ?, ?> attributable);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/Entity.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/Entity.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/Entity.java
index b1b4e00..6c8afbd 100644
--- a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/Entity.java
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/Entity.java
@@ -18,7 +18,9 @@
*/
package org.apache.syncope.persistence.api.entity;
-public interface Entity<KEY> {
+import java.io.Serializable;
+
+public interface Entity<KEY> extends Serializable {
KEY getKey();
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/EntityFactory.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/EntityFactory.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/EntityFactory.java
index 58af4f8..c36030b 100644
--- a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/EntityFactory.java
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/EntityFactory.java
@@ -23,4 +23,6 @@ public interface EntityFactory {
<KEY, T extends Entity<KEY>> T newEntity(Class<T> reference);
<T extends Policy> T newPolicy(Class<T> reference, boolean global);
+
+ ConnPoolConf newConnPoolConf();
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/ExternalResource.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/ExternalResource.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/ExternalResource.java
index 965c1a5..8e55c26 100644
--- a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/ExternalResource.java
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/ExternalResource.java
@@ -27,7 +27,7 @@ import org.apache.syncope.common.lib.types.PropagationMode;
import org.apache.syncope.common.lib.types.TraceLevel;
import org.identityconnectors.framework.common.objects.SyncToken;
-public interface ExternalResource extends Entity<String> {
+public interface ExternalResource extends AnnotatedEntity<String> {
AccountPolicy getAccountPolicy();
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/role/Role.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/role/Role.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/role/Role.java
index 0c3ac50..b61afdc 100644
--- a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/role/Role.java
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/role/Role.java
@@ -92,7 +92,7 @@ public interface Role extends Subject<RPlainAttr, RDerAttr, RVirAttr> {
boolean isInheritAccountPolicy();
- boolean isInheritAttrs();
+ boolean isInheritPlainAttrs();
boolean isInheritDerAttrs();
@@ -108,7 +108,7 @@ public interface Role extends Subject<RPlainAttr, RDerAttr, RVirAttr> {
void setInheritAccountPolicy(boolean condition);
- void setInheritAttrs(boolean inheritAttrs);
+ void setInheritPlainAttrs(boolean inheritAttrs);
void setInheritDerAttrs(boolean inheritDerAttrs);
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/task/TaskUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/task/TaskUtil.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/task/TaskUtil.java
new file mode 100644
index 0000000..661c645
--- /dev/null
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/task/TaskUtil.java
@@ -0,0 +1,36 @@
+/*
+ * 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.persistence.api.entity.task;
+
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.types.TaskType;
+
+public interface TaskUtil {
+
+ TaskType getType();
+
+ <T extends Task> T newTask();
+
+ <T extends AbstractTaskTO> T newTaskTO();
+
+ <T extends Task> Class<T> taskClass();
+
+ <T extends AbstractTaskTO> Class<T> taskTOClass();
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/task/TaskUtilFactory.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/task/TaskUtilFactory.java b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/task/TaskUtilFactory.java
new file mode 100644
index 0000000..b2b24e6
--- /dev/null
+++ b/syncope620/server/persistence-api/src/main/java/org/apache/syncope/persistence/api/entity/task/TaskUtilFactory.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.persistence.api.entity.task;
+
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.types.TaskType;
+
+public interface TaskUtilFactory {
+
+ TaskUtil getInstance(TaskType type);
+
+ TaskUtil getInstance(Task task);
+
+ TaskUtil getInstance(Class<? extends AbstractTaskTO> taskClass);
+
+ TaskUtil getInstance(AbstractTaskTO taskTO);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/pom.xml b/syncope620/server/persistence-jpa/pom.xml
index 17b6a92..b5f0bbe 100644
--- a/syncope620/server/persistence-jpa/pom.xml
+++ b/syncope620/server/persistence-jpa/pom.xml
@@ -91,7 +91,7 @@ under the License.
<dependency>
<groupId>org.apache.syncope.server</groupId>
- <artifactId>syncope-provisioning-api</artifactId>
+ <artifactId>syncope-provisioning-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/AbstractSubjectDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/AbstractSubjectDAO.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/AbstractSubjectDAO.java
index ac6ab68..64712c8 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/AbstractSubjectDAO.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/AbstractSubjectDAO.java
@@ -89,10 +89,10 @@ abstract class AbstractSubjectDAO<P extends PlainAttr, D extends DerAttr, V exte
final Parser parser = new Parser(new StringReader(expression));
// Schema names
- final List<String> identifiers = new ArrayList<String>();
+ final List<String> identifiers = new ArrayList<>();
// Literals
- final List<String> literals = new ArrayList<String>();
+ final List<String> literals = new ArrayList<>();
// Get schema names and literals
Token token;
@@ -131,18 +131,18 @@ abstract class AbstractSubjectDAO<P extends PlainAttr, D extends DerAttr, V exte
final List<String> attrValues = split(value, literals);
if (attrValues.size() != identifiers.size()) {
- LOG.error("Ambiguous jexl expression resolution.");
+ LOG.error("Ambiguous JEXL expression resolution.");
throw new IllegalArgumentException("literals and values have different size");
}
// clauses to be used with INTERSECTed queries
- final Set<String> clauses = new HashSet<String>();
+ final Set<String> clauses = new HashSet<>();
// builder to build the clauses
final StringBuilder bld = new StringBuilder();
// Contains used identifiers in order to avoid replications
- final Set<String> used = new HashSet<String>();
+ final Set<String> used = new HashSet<>();
// Create several clauses: one for eanch identifiers
for (int i = 0; i < identifiers.size(); i++) {
[07/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConfigurationDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConfigurationDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConfigurationDataBinder.java
new file mode 100644
index 0000000..64c4a4e
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConfigurationDataBinder.java
@@ -0,0 +1,75 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.Collections;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ConfTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.persistence.api.entity.conf.CPlainSchema;
+import org.apache.syncope.persistence.api.entity.conf.Conf;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ConfigurationDataBinder extends AbstractAttributableDataBinder {
+
+ public ConfTO getConfTO(final Conf conf) {
+ final ConfTO confTO = new ConfTO();
+ confTO.setKey(conf.getKey());
+
+ fillTO(confTO, conf.getPlainAttrs(),
+ conf.getDerAttrs(), conf.getVirAttrs(), Collections.<ExternalResource>emptySet());
+
+ return confTO;
+ }
+
+ public AttrTO getAttrTO(final CPlainAttr attr) {
+ final AttrTO attributeTO = new AttrTO();
+ attributeTO.setSchema(attr.getSchema().getKey());
+ attributeTO.getValues().addAll(attr.getValuesAsStrings());
+ attributeTO.setReadonly(attr.getSchema().isReadonly());
+
+ return attributeTO;
+ }
+
+ public CPlainAttr getAttribute(final AttrTO attributeTO) {
+ CPlainSchema schema = getPlainSchema(attributeTO.getSchema(), CPlainSchema.class);
+ if (schema == null) {
+ throw new NotFoundException("Conf schema " + attributeTO.getSchema());
+ } else {
+ SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
+ CPlainAttr attr = entityFactory.newEntity(CPlainAttr.class);
+ attr.setSchema(schema);
+ fillAttribute(attributeTO.getValues(), attrUtilFactory.getInstance(AttributableType.CONFIGURATION),
+ schema, attr, invalidValues);
+
+ if (!invalidValues.isEmpty()) {
+ throw invalidValues;
+ }
+ return attr;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConnInstanceDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConnInstanceDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConnInstanceDataBinder.java
new file mode 100644
index 0000000..1091be1
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ConnInstanceDataBinder.java
@@ -0,0 +1,246 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.ConnInstanceTO;
+import org.apache.syncope.common.lib.to.ConnPoolConfTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ConnConfPropSchema;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.persistence.api.dao.ConnInstanceDAO;
+import org.apache.syncope.persistence.api.entity.ConnInstance;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.provisioning.api.ConnIdBundleManager;
+import org.apache.syncope.provisioning.api.ConnPoolConfUtil;
+import org.identityconnectors.framework.api.ConfigurationProperties;
+import org.identityconnectors.framework.api.ConfigurationProperty;
+import org.identityconnectors.framework.impl.api.ConfigurationPropertyImpl;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ConnInstanceDataBinder {
+
+ private static final String[] IGNORE_PROPERTIES = { "key", "poolConf" };
+
+ @Autowired
+ private ConnIdBundleManager connIdBundleManager;
+
+ @Autowired
+ private ConnInstanceDAO connInstanceDAO;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ /**
+ * Merge connector configuration properties avoiding repetition but giving priority to primary set.
+ *
+ * @param primary primary set.
+ * @param secondary secondary set.
+ * @return merged set.
+ */
+ public Set<ConnConfProperty> mergeConnConfProperties(final Set<ConnConfProperty> primary,
+ final Set<ConnConfProperty> secondary) {
+
+ final Set<ConnConfProperty> conf = new HashSet<>();
+
+ // to be used to control managed prop (needed by overridden mechanism)
+ final Set<String> propertyNames = new HashSet<>();
+
+ // get overridden connector configuration properties
+ for (ConnConfProperty prop : primary) {
+ if (!propertyNames.contains(prop.getSchema().getName())) {
+ conf.add(prop);
+ propertyNames.add(prop.getSchema().getName());
+ }
+ }
+
+ // get connector configuration properties
+ for (ConnConfProperty prop : secondary) {
+ if (!propertyNames.contains(prop.getSchema().getName())) {
+ conf.add(prop);
+ propertyNames.add(prop.getSchema().getName());
+ }
+ }
+
+ return conf;
+ }
+
+ public ConnInstance getConnInstance(final ConnInstanceTO connInstanceTO) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+
+ if (connInstanceTO.getLocation() == null) {
+ sce.getElements().add("location");
+ }
+
+ if (connInstanceTO.getBundleName() == null) {
+ sce.getElements().add("bundlename");
+ }
+
+ if (connInstanceTO.getVersion() == null) {
+ sce.getElements().add("bundleversion");
+ }
+
+ if (connInstanceTO.getConnectorName() == null) {
+ sce.getElements().add("connectorname");
+ }
+
+ if (connInstanceTO.getConfiguration() == null || connInstanceTO.getConfiguration().isEmpty()) {
+ sce.getElements().add("configuration");
+ }
+
+ ConnInstance connInstance = entityFactory.newEntity(ConnInstance.class);
+
+ BeanUtils.copyProperties(connInstanceTO, connInstance, IGNORE_PROPERTIES);
+ if (connInstanceTO.getLocation() != null) {
+ connInstance.setLocation(connInstanceTO.getLocation());
+ }
+ if (connInstanceTO.getPoolConf() != null) {
+ connInstance.setPoolConf(
+ ConnPoolConfUtil.getConnPoolConf(connInstanceTO.getPoolConf(), entityFactory.newConnPoolConf()));
+ }
+
+ // Throw exception if there is at least one element set
+ if (!sce.isEmpty()) {
+ throw sce;
+ }
+
+ return connInstance;
+ }
+
+ public ConnInstance updateConnInstance(final long connInstanceId, final ConnInstanceTO connInstanceTO) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+
+ if (connInstanceId == 0) {
+ sce.getElements().add("connector id");
+ }
+
+ ConnInstance connInstance = connInstanceDAO.find(connInstanceId);
+ connInstance.getCapabilities().clear();
+ connInstance.getCapabilities().addAll(connInstanceTO.getCapabilities());
+
+ if (connInstanceTO.getLocation() != null) {
+ connInstance.setLocation(connInstanceTO.getLocation());
+ }
+
+ if (connInstanceTO.getBundleName() != null) {
+ connInstance.setBundleName(connInstanceTO.getBundleName());
+ }
+
+ if (connInstanceTO.getVersion() != null) {
+ connInstance.setVersion(connInstanceTO.getVersion());
+ }
+
+ if (connInstanceTO.getConnectorName() != null) {
+ connInstance.setConnectorName(connInstanceTO.getConnectorName());
+ }
+
+ if (connInstanceTO.getConfiguration() != null && !connInstanceTO.getConfiguration().isEmpty()) {
+ connInstance.setConfiguration(connInstanceTO.getConfiguration());
+ }
+
+ if (connInstanceTO.getDisplayName() != null) {
+ connInstance.setDisplayName(connInstanceTO.getDisplayName());
+ }
+
+ if (connInstanceTO.getConnRequestTimeout() != null) {
+ connInstance.setConnRequestTimeout(connInstanceTO.getConnRequestTimeout());
+ }
+
+ if (connInstanceTO.getPoolConf() == null) {
+ connInstance.setPoolConf(null);
+ } else {
+ connInstance.setPoolConf(
+ ConnPoolConfUtil.getConnPoolConf(connInstanceTO.getPoolConf(), entityFactory.newConnPoolConf()));
+ }
+
+ if (!sce.isEmpty()) {
+ throw sce;
+ }
+
+ return connInstance;
+ }
+
+ public ConnConfPropSchema buildConnConfPropSchema(final ConfigurationProperty property) {
+ ConnConfPropSchema connConfPropSchema = new ConnConfPropSchema();
+
+ connConfPropSchema.setName(property.getName());
+ connConfPropSchema.setDisplayName(property.getDisplayName(property.getName()));
+ connConfPropSchema.setHelpMessage(property.getHelpMessage(property.getName()));
+ connConfPropSchema.setRequired(property.isRequired());
+ connConfPropSchema.setType(property.getType().getName());
+ connConfPropSchema.setOrder(((ConfigurationPropertyImpl) property).getOrder());
+ connConfPropSchema.setConfidential(property.isConfidential());
+
+ if (property.getValue() != null) {
+ if (property.getValue().getClass().isArray()) {
+ connConfPropSchema.getDefaultValues().addAll(Arrays.asList((Object[]) property.getValue()));
+ } else if (property.getValue() instanceof Collection<?>) {
+ connConfPropSchema.getDefaultValues().addAll((Collection<?>) property.getValue());
+ } else {
+ connConfPropSchema.getDefaultValues().add(property.getValue());
+ }
+ }
+
+ return connConfPropSchema;
+ }
+
+ public ConnInstanceTO getConnInstanceTO(final ConnInstance connInstance) {
+ ConnInstanceTO connInstanceTO = new ConnInstanceTO();
+ connInstanceTO.setKey(connInstance.getKey() == null ? 0L : connInstance.getKey());
+
+ // retrieve the ConfigurationProperties
+ ConfigurationProperties properties = connIdBundleManager.getConfigurationProperties(
+ connIdBundleManager.getConnectorInfo(connInstance.getLocation(),
+ connInstance.getBundleName(), connInstance.getVersion(), connInstance.getConnectorName()));
+
+ BeanUtils.copyProperties(connInstance, connInstanceTO, IGNORE_PROPERTIES);
+
+ final Map<String, ConnConfProperty> connInstanceToConfMap = connInstanceTO.getConfigurationMap();
+
+ for (String propName : properties.getPropertyNames()) {
+ ConnConfPropSchema schema = buildConnConfPropSchema(properties.getProperty(propName));
+
+ ConnConfProperty property;
+ if (connInstanceToConfMap.containsKey(propName)) {
+ property = connInstanceToConfMap.get(propName);
+ } else {
+ property = new ConnConfProperty();
+ connInstanceTO.getConfiguration().add(property);
+ }
+
+ property.setSchema(schema);
+ }
+
+ if (connInstance.getPoolConf() != null) {
+ ConnPoolConfTO poolConf = new ConnPoolConfTO();
+ BeanUtils.copyProperties(connInstance.getPoolConf(), poolConf);
+ connInstanceTO.setPoolConf(poolConf);
+ }
+
+ return connInstanceTO;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/NotificationDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/NotificationDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/NotificationDataBinder.java
new file mode 100644
index 0000000..0ddb74e
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/NotificationDataBinder.java
@@ -0,0 +1,62 @@
+/*
+ * 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.server.logic.data;
+
+import org.apache.syncope.common.lib.to.NotificationTO;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.Notification;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class NotificationDataBinder {
+
+ private static final String[] IGNORE_PROPERTIES = { "key", "about", "recipients" };
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ public NotificationTO getNotificationTO(final Notification notification) {
+ NotificationTO result = new NotificationTO();
+
+ BeanUtils.copyProperties(notification, result, IGNORE_PROPERTIES);
+
+ result.setKey(notification.getKey());
+ result.setUserAbout(notification.getUserAbout());
+ result.setRoleAbout(notification.getRoleAbout());
+ result.setRecipients(notification.getRecipients());
+
+ return result;
+ }
+
+ public Notification create(final NotificationTO notificationTO) {
+ Notification result = entityFactory.newEntity(Notification.class);
+ update(result, notificationTO);
+ return result;
+ }
+
+ public void update(final Notification notification, final NotificationTO notificationTO) {
+ BeanUtils.copyProperties(notificationTO, notification, IGNORE_PROPERTIES);
+
+ notification.setUserAbout(notificationTO.getUserAbout());
+ notification.setRoleAbout(notificationTO.getRoleAbout());
+ notification.setRecipients(notificationTO.getRecipients());
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/PolicyDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/PolicyDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/PolicyDataBinder.java
new file mode 100644
index 0000000..57877d2
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/PolicyDataBinder.java
@@ -0,0 +1,186 @@
+/*
+ * 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.server.logic.data;
+
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractPolicyTO;
+import org.apache.syncope.common.lib.to.AccountPolicyTO;
+import org.apache.syncope.common.lib.to.PasswordPolicyTO;
+import org.apache.syncope.common.lib.to.SyncPolicyTO;
+import org.apache.syncope.common.lib.types.AccountPolicySpec;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.PasswordPolicySpec;
+import org.apache.syncope.common.lib.types.SyncPolicySpec;
+import org.apache.syncope.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.entity.AccountPolicy;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.persistence.api.entity.Policy;
+import org.apache.syncope.persistence.api.entity.SyncPolicy;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PolicyDataBinder {
+
+ /**
+ * Logger.
+ */
+ protected static final Logger LOG = LoggerFactory.getLogger(PolicyDataBinder.class);
+
+ @Autowired
+ private ExternalResourceDAO resourceDAO;
+
+ @Autowired
+ private RoleDAO roleDAO;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ /**
+ * Get policy TO from policy bean.
+ *
+ * @param policy bean.
+ * @return policy TO.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends AbstractPolicyTO> T getPolicyTO(final Policy policy) {
+ final T policyTO;
+
+ switch (policy.getType()) {
+ case GLOBAL_PASSWORD:
+ case PASSWORD:
+ policyTO = (T) new PasswordPolicyTO(policy.getType().isGlobal());
+ ((PasswordPolicyTO) policyTO).setSpecification(policy.getSpecification(PasswordPolicySpec.class));
+ break;
+
+ case GLOBAL_ACCOUNT:
+ case ACCOUNT:
+ policyTO = (T) new AccountPolicyTO(policy.getType().isGlobal());
+ ((AccountPolicyTO) policyTO).setSpecification(policy.getSpecification(AccountPolicySpec.class));
+ ((AccountPolicyTO) policyTO).getResources().addAll(((AccountPolicy) policy).getResourceNames());
+ break;
+
+ case GLOBAL_SYNC:
+ case SYNC:
+ default:
+ policyTO = (T) new SyncPolicyTO(policy.getType().isGlobal());
+ ((SyncPolicyTO) policyTO).setSpecification(policy.getSpecification(SyncPolicySpec.class));
+ }
+
+ policyTO.setId(policy.getKey());
+ policyTO.setDescription(policy.getDescription());
+
+ for (ExternalResource resource : resourceDAO.findByPolicy(policy)) {
+ policyTO.getUsedByResources().add(resource.getKey());
+ }
+ if (policy.getType().isGlobal()) {
+ for (ExternalResource resource : resourceDAO.findWithoutPolicy(policy.getType())) {
+ policyTO.getUsedByResources().add(resource.getKey());
+ }
+ }
+ for (Role role : roleDAO.findByPolicy(policy)) {
+ policyTO.getUsedByRoles().add(role.getKey());
+ }
+ if (policy.getType().isGlobal()) {
+ for (Role role : roleDAO.findWithoutPolicy(policy.getType())) {
+ policyTO.getUsedByRoles().add(role.getKey());
+ }
+ }
+
+ return policyTO;
+ }
+
+ private ExternalResource getResource(final String resourceName) {
+ ExternalResource resource = resourceDAO.find(resourceName);
+ if (resource == null) {
+ LOG.debug("Ignoring invalid resource {} ", resourceName);
+ }
+
+ return resource;
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T extends Policy> T getPolicy(T policy, final AbstractPolicyTO policyTO) {
+ if (policy != null && policy.getType() != policyTO.getType()) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidPolicy);
+ sce.getElements().add(String.format("Cannot update %s from %s", policy.getType(), policyTO.getType()));
+ throw sce;
+ }
+
+ switch (policyTO.getType()) {
+ case GLOBAL_PASSWORD:
+ case PASSWORD:
+ if (!(policyTO instanceof PasswordPolicyTO)) {
+ throw new ClassCastException("Expected " + PasswordPolicyTO.class.getName()
+ + ", found " + policyTO.getClass().getName());
+ }
+ if (policy == null) {
+ policy = (T) entityFactory.newPolicy(PasswordPolicy.class, policyTO.getType().isGlobal());
+ }
+ policy.setSpecification(((PasswordPolicyTO) policyTO).getSpecification());
+ break;
+
+ case GLOBAL_ACCOUNT:
+ case ACCOUNT:
+ if (!(policyTO instanceof AccountPolicyTO)) {
+ throw new ClassCastException("Expected " + AccountPolicyTO.class.getName()
+ + ", found " + policyTO.getClass().getName());
+ }
+ if (policy == null) {
+ policy = (T) entityFactory.newPolicy(AccountPolicy.class, policyTO.getType().isGlobal());
+ }
+ policy.setSpecification(((AccountPolicyTO) policyTO).getSpecification());
+
+ if (((AccountPolicy) policy).getResources() != null
+ && !((AccountPolicy) policy).getResources().isEmpty()) {
+ ((AccountPolicy) policy).getResources().clear();
+ }
+ for (String resourceName : ((AccountPolicyTO) policyTO).getResources()) {
+ ExternalResource resource = getResource(resourceName);
+
+ if (resource != null) {
+ ((AccountPolicy) policy).addResource(resource);
+ }
+ }
+ break;
+
+ case GLOBAL_SYNC:
+ case SYNC:
+ default:
+ if (!(policyTO instanceof SyncPolicyTO)) {
+ throw new ClassCastException("Expected " + SyncPolicyTO.class.getName()
+ + ", found " + policyTO.getClass().getName());
+ }
+ if (policy == null) {
+ policy = (T) entityFactory.newPolicy(SyncPolicy.class, policyTO.getType().isGlobal());
+ }
+ policy.setSpecification(((SyncPolicyTO) policyTO).getSpecification());
+ }
+
+ policy.setDescription(policyTO.getDescription());
+
+ return policy;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ReportDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ReportDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ReportDataBinder.java
new file mode 100644
index 0000000..952de94
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ReportDataBinder.java
@@ -0,0 +1,175 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.syncope.common.lib.report.AbstractReportletConf;
+import org.apache.syncope.common.lib.report.ReportletConf;
+import org.apache.syncope.common.lib.to.ReportExecTO;
+import org.apache.syncope.common.lib.to.ReportTO;
+import org.apache.syncope.persistence.api.dao.ReportExecDAO;
+import org.apache.syncope.persistence.api.entity.Report;
+import org.apache.syncope.persistence.api.entity.ReportExec;
+import org.apache.syncope.server.logic.init.ImplementationClassNamesLoader;
+import org.apache.syncope.server.logic.report.Reportlet;
+import org.apache.syncope.server.logic.init.JobInstanceLoader;
+import org.apache.syncope.server.logic.report.ReportletConfClass;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.TriggerKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ClassUtils;
+
+@Component
+public class ReportDataBinder {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(ReportDataBinder.class);
+
+ private static final String[] IGNORE_REPORT_PROPERTIES = { "key", "reportlets", "executions" };
+
+ private static final String[] IGNORE_REPORT_EXECUTION_PROPERTIES = { "key", "report", "execResult" };
+
+ @Autowired
+ private ReportExecDAO reportExecDAO;
+
+ @Autowired
+ private SchedulerFactoryBean scheduler;
+
+ @Autowired
+ private ImplementationClassNamesLoader classNamesLoader;
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public Set<Class<Reportlet>> getAllReportletClasses() {
+ Set<Class<Reportlet>> reportletClasses = new HashSet<Class<Reportlet>>();
+
+ for (String className : classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.REPORTLET)) {
+ try {
+ Class reportletClass = ClassUtils.forName(className, ClassUtils.getDefaultClassLoader());
+ reportletClasses.add(reportletClass);
+ } catch (ClassNotFoundException e) {
+ LOG.warn("Could not load class {}", className);
+ } catch (LinkageError e) {
+ LOG.warn("Could not link class {}", className);
+ }
+ }
+ return reportletClasses;
+ }
+
+ public Class<? extends ReportletConf> getReportletConfClass(final Class<Reportlet> reportletClass) {
+ Class<? extends ReportletConf> result = null;
+
+ ReportletConfClass annotation = reportletClass.getAnnotation(ReportletConfClass.class);
+ if (annotation != null) {
+ result = annotation.value();
+ }
+
+ return result;
+ }
+
+ public Class<Reportlet> findReportletClassHavingConfClass(final Class<? extends ReportletConf> reportletConfClass) {
+ Class<Reportlet> result = null;
+ for (Class<Reportlet> reportletClass : getAllReportletClasses()) {
+ Class<? extends ReportletConf> found = getReportletConfClass(reportletClass);
+ if (found != null && found.equals(reportletConfClass)) {
+ result = reportletClass;
+ }
+ }
+
+ return result;
+ }
+
+ public void getReport(final Report report, final ReportTO reportTO) {
+ BeanUtils.copyProperties(reportTO, report, IGNORE_REPORT_PROPERTIES);
+ report.getReportletConfs().clear();
+ for (ReportletConf conf : reportTO.getReportletConfs()) {
+ report.addReportletConf(conf);
+ }
+ }
+
+ public ReportTO getReportTO(final Report report) {
+ ReportTO reportTO = new ReportTO();
+ reportTO.setId(report.getKey());
+ BeanUtils.copyProperties(report, reportTO, IGNORE_REPORT_PROPERTIES);
+
+ copyReportletConfs(report, reportTO);
+
+ ReportExec latestExec = reportExecDAO.findLatestStarted(report);
+ reportTO.setLatestExecStatus(latestExec == null
+ ? ""
+ : latestExec.getStatus());
+
+ reportTO.setStartDate(latestExec == null
+ ? null
+ : latestExec.getStartDate());
+
+ reportTO.setEndDate(latestExec == null
+ ? null
+ : latestExec.getEndDate());
+
+ for (ReportExec reportExec : report.getExecs()) {
+ reportTO.getExecutions().add(getReportExecTO(reportExec));
+ }
+
+ String triggerName = JobInstanceLoader.getTriggerName(JobInstanceLoader.getJobName(report));
+
+ Trigger trigger;
+ try {
+ trigger = scheduler.getScheduler().getTrigger(new TriggerKey(triggerName, Scheduler.DEFAULT_GROUP));
+ } catch (SchedulerException e) {
+ LOG.warn("While trying to get to " + triggerName, e);
+ trigger = null;
+ }
+
+ if (trigger != null) {
+ reportTO.setLastExec(trigger.getPreviousFireTime());
+ reportTO.setNextExec(trigger.getNextFireTime());
+ }
+
+ return reportTO;
+ }
+
+ private void copyReportletConfs(final Report report, final ReportTO reportTO) {
+ reportTO.getReportletConfs().clear();
+ for (ReportletConf reportletConf : report.getReportletConfs()) {
+ reportTO.getReportletConfs().add((AbstractReportletConf) reportletConf);
+ }
+ }
+
+ public ReportExecTO getReportExecTO(final ReportExec execution) {
+ ReportExecTO executionTO = new ReportExecTO();
+ executionTO.setKey(execution.getKey());
+ BeanUtils.copyProperties(execution, executionTO, IGNORE_REPORT_EXECUTION_PROPERTIES);
+ if (execution.getKey() != null) {
+ executionTO.setKey(execution.getKey());
+ }
+ executionTO.setReport(execution.getReport().getKey());
+
+ return executionTO;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ResourceDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ResourceDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ResourceDataBinder.java
new file mode 100644
index 0000000..b307eee
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/ResourceDataBinder.java
@@ -0,0 +1,389 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.MappingItemTO;
+import org.apache.syncope.common.lib.to.MappingTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.persistence.api.dao.ConnInstanceDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.PolicyDAO;
+import org.apache.syncope.persistence.api.entity.AccountPolicy;
+import org.apache.syncope.persistence.api.entity.ConnInstance;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.Mapping;
+import org.apache.syncope.persistence.api.entity.MappingItem;
+import org.apache.syncope.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.persistence.api.entity.SyncPolicy;
+import org.apache.syncope.persistence.api.entity.role.RMapping;
+import org.apache.syncope.persistence.api.entity.role.RMappingItem;
+import org.apache.syncope.persistence.api.entity.user.UMapping;
+import org.apache.syncope.persistence.api.entity.user.UMappingItem;
+import org.apache.syncope.server.utils.jexl.JexlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ResourceDataBinder {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(ResourceDataBinder.class);
+
+ private static final String[] MAPPINGITEM_IGNORE_PROPERTIES = { "key", "mapping" };
+
+ @Autowired
+ private ConnInstanceDAO connInstanceDAO;
+
+ @Autowired
+ private PolicyDAO policyDAO;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ public ExternalResource create(final ResourceTO resourceTO) {
+ return update(entityFactory.newEntity(ExternalResource.class), resourceTO);
+ }
+
+ public ExternalResource update(final ExternalResource resource, final ResourceTO resourceTO) {
+ if (resourceTO == null) {
+ return null;
+ }
+
+ resource.setKey(resourceTO.getKey());
+
+ if (resourceTO.getConnectorId() != null) {
+ ConnInstance connector = connInstanceDAO.find(resourceTO.getConnectorId());
+ resource.setConnector(connector);
+
+ if (!connector.getResources().contains(resource)) {
+ connector.addResource(resource);
+ }
+ }
+
+ resource.setEnforceMandatoryCondition(resourceTO.isEnforceMandatoryCondition());
+
+ resource.setPropagationPrimary(resourceTO.isPropagationPrimary());
+
+ resource.setPropagationPriority(resourceTO.getPropagationPriority());
+
+ resource.setRandomPwdIfNotProvided(resourceTO.isRandomPwdIfNotProvided());
+
+ resource.setPropagationMode(resourceTO.getPropagationMode());
+
+ if (resourceTO.getUmapping() == null || resourceTO.getUmapping().getItems().isEmpty()) {
+ resource.setUmapping(null);
+ } else {
+ UMapping mapping = entityFactory.newEntity(UMapping.class);
+ mapping.setResource(resource);
+ resource.setUmapping(mapping);
+ populateMapping(resourceTO.getUmapping(), mapping, entityFactory.newEntity(UMappingItem.class));
+ }
+ if (resourceTO.getRmapping() == null || resourceTO.getRmapping().getItems().isEmpty()) {
+ resource.setRmapping(null);
+ } else {
+ RMapping mapping = entityFactory.newEntity(RMapping.class);
+ mapping.setResource(resource);
+ resource.setRmapping(mapping);
+ populateMapping(resourceTO.getRmapping(), mapping, entityFactory.newEntity(RMappingItem.class));
+ }
+
+ resource.setCreateTraceLevel(resourceTO.getCreateTraceLevel());
+ resource.setUpdateTraceLevel(resourceTO.getUpdateTraceLevel());
+ resource.setDeleteTraceLevel(resourceTO.getDeleteTraceLevel());
+ resource.setSyncTraceLevel(resourceTO.getSyncTraceLevel());
+
+ resource.setPasswordPolicy(resourceTO.getPasswordPolicy() == null
+ ? null : (PasswordPolicy) policyDAO.find(resourceTO.getPasswordPolicy()));
+
+ resource.setAccountPolicy(resourceTO.getAccountPolicy() == null
+ ? null : (AccountPolicy) policyDAO.find(resourceTO.getAccountPolicy()));
+
+ resource.setSyncPolicy(resourceTO.getSyncPolicy() == null
+ ? null : (SyncPolicy) policyDAO.find(resourceTO.getSyncPolicy()));
+
+ resource.setConnInstanceConfiguration(new HashSet<>(resourceTO.getConnConfProperties()));
+
+ if (resourceTO.getUsyncToken() == null) {
+ resource.setUsyncToken(null);
+ }
+ if (resourceTO.getRsyncToken() == null) {
+ resource.setRsyncToken(null);
+ }
+
+ resource.getPropagationActionsClassNames().clear();
+ resource.getPropagationActionsClassNames().addAll(resourceTO.getPropagationActionsClassNames());
+
+ return resource;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ private void populateMapping(final MappingTO mappingTO, final Mapping mapping, final MappingItem prototype) {
+ mapping.setAccountLink(mappingTO.getAccountLink());
+
+ for (MappingItem item : getMappingItems(mappingTO.getItems(), prototype)) {
+ item.setMapping(mapping);
+ if (item.isAccountid()) {
+ mapping.setAccountIdItem(item);
+ } else if (item.isPassword()) {
+ ((UMapping) mapping).setPasswordItem((UMappingItem) item);
+ } else {
+ mapping.addItem(item);
+ }
+ }
+ }
+
+ private Set<MappingItem> getMappingItems(final Collection<MappingItemTO> itemTOs, final MappingItem prototype) {
+ Set<MappingItem> items = new HashSet<>(itemTOs.size());
+ for (MappingItemTO itemTO : itemTOs) {
+ items.add(getMappingItem(itemTO, prototype));
+ }
+
+ return items;
+ }
+
+ private MappingItem getMappingItem(final MappingItemTO itemTO, final MappingItem prototype) {
+ if (itemTO == null || itemTO.getIntMappingType() == null) {
+ LOG.error("Null mappingTO provided");
+ return null;
+ }
+
+ SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+ SyncopeClientException requiredValuesMissing = SyncopeClientException.build(
+ ClientExceptionType.RequiredValuesMissing);
+
+ if (itemTO.getIntAttrName() == null) {
+ if (IntMappingType.getEmbedded().contains(itemTO.getIntMappingType())) {
+ itemTO.setIntAttrName(itemTO.getIntMappingType().toString());
+ } else {
+ requiredValuesMissing.getElements().add("intAttrName");
+ }
+ }
+
+ // Throw composite exception if there is at least one element set
+ // in the composing exceptions
+ if (!requiredValuesMissing.isEmpty()) {
+ scce.addException(requiredValuesMissing);
+ }
+
+ // no mandatory condition implies mandatory condition false
+ if (!JexlUtil.isExpressionValid(itemTO.getMandatoryCondition() == null
+ ? "false" : itemTO.getMandatoryCondition())) {
+
+ SyncopeClientException invalidMandatoryCondition = SyncopeClientException.build(
+ ClientExceptionType.InvalidValues);
+
+ invalidMandatoryCondition.getElements().add(itemTO.getMandatoryCondition());
+
+ scce.addException(invalidMandatoryCondition);
+ }
+
+ if (scce.hasExceptions()) {
+ throw scce;
+ }
+
+ MappingItem item = SerializationUtils.clone(prototype);
+ BeanUtils.copyProperties(itemTO, item, MAPPINGITEM_IGNORE_PROPERTIES);
+ return item;
+ }
+
+ public ConnInstance getConnInstance(final ExternalResource resource) {
+ final ConnInstance connInstanceClone = SerializationUtils.clone(resource.getConnector());
+ return getConnInstance(connInstanceClone, resource.getConnInstanceConfiguration());
+ }
+
+ public ConnInstance getConnInstance(final ResourceTO resourceTO) {
+ ConnInstance connInstance = connInstanceDAO.find(resourceTO.getConnectorId());
+ if (connInstance == null) {
+ throw new NotFoundException("Connector '" + resourceTO.getConnectorId() + "'");
+ }
+
+ final ConnInstance connInstanceClone = SerializationUtils.clone(connInstance);
+ return getConnInstance(connInstanceClone, resourceTO.getConnConfProperties());
+ }
+
+ private ConnInstance getConnInstance(final ConnInstance connInstance, final Set<ConnConfProperty> overridden) {
+ final Set<ConnConfProperty> configuration = new HashSet<>();
+ final Map<String, ConnConfProperty> overridable = new HashMap<>();
+
+ // add not overridable properties
+ for (ConnConfProperty prop : connInstance.getConfiguration()) {
+ if (prop.isOverridable()) {
+ overridable.put(prop.getSchema().getName(), prop);
+ } else {
+ configuration.add(prop);
+ }
+ }
+
+ // add overridden properties
+ for (ConnConfProperty prop : overridden) {
+ if (overridable.containsKey(prop.getSchema().getName()) && !prop.getValues().isEmpty()) {
+ configuration.add(prop);
+ overridable.remove(prop.getSchema().getName());
+ }
+ }
+
+ // add overridable properties not overridden
+ configuration.addAll(overridable.values());
+
+ connInstance.setConfiguration(configuration);
+
+ return connInstance;
+ }
+
+ public List<ResourceTO> getResourceTOs(final Collection<? extends ExternalResource> resources) {
+ List<ResourceTO> resourceTOs = new ArrayList<>();
+ for (ExternalResource resource : resources) {
+ resourceTOs.add(getResourceTO(resource));
+ }
+
+ return resourceTOs;
+ }
+
+ public ResourceTO getResourceTO(final ExternalResource resource) {
+ if (resource == null) {
+ return null;
+ }
+
+ ResourceTO resourceTO = new ResourceTO();
+
+ // set sys info
+ resourceTO.setCreator(resource.getCreator());
+ resourceTO.setCreationDate(resource.getCreationDate());
+ resourceTO.setLastModifier(resource.getLastModifier());
+ resourceTO.setLastChangeDate(resource.getLastChangeDate());
+
+ // set the resource name
+ resourceTO.setKey(resource.getKey());
+
+ // set the connector instance
+ ConnInstance connector = resource.getConnector();
+
+ resourceTO.setConnectorId(connector == null ? null : connector.getKey());
+ resourceTO.setConnectorDisplayName(connector == null ? null : connector.getDisplayName());
+
+ // set the mappings
+ if (resource.getUmapping() != null) {
+ MappingTO mappingTO = new MappingTO();
+ resourceTO.setUmapping(mappingTO);
+ populateMappingTO(resource.getUmapping(), mappingTO);
+ }
+ if (resource.getRmapping() != null) {
+ MappingTO mappingTO = new MappingTO();
+ resourceTO.setRmapping(mappingTO);
+ populateMappingTO(resource.getRmapping(), mappingTO);
+ }
+
+ resourceTO.setEnforceMandatoryCondition(resource.isEnforceMandatoryCondition());
+
+ resourceTO.setPropagationPrimary(resource.isPropagationPrimary());
+
+ resourceTO.setPropagationPriority(resource.getPropagationPriority());
+
+ resourceTO.setRandomPwdIfNotProvided(resource.isRandomPwdIfNotProvided());
+
+ resourceTO.setPropagationMode(resource.getPropagationMode());
+
+ resourceTO.setCreateTraceLevel(resource.getCreateTraceLevel());
+ resourceTO.setUpdateTraceLevel(resource.getUpdateTraceLevel());
+ resourceTO.setDeleteTraceLevel(resource.getDeleteTraceLevel());
+ resourceTO.setSyncTraceLevel(resource.getSyncTraceLevel());
+
+ resourceTO.setPasswordPolicy(resource.getPasswordPolicy() == null
+ ? null : resource.getPasswordPolicy().getKey());
+
+ resourceTO.setAccountPolicy(resource.getAccountPolicy() == null
+ ? null : resource.getAccountPolicy().getKey());
+
+ resourceTO.setSyncPolicy(resource.getSyncPolicy() == null
+ ? null : resource.getSyncPolicy().getKey());
+
+ resourceTO.getConnConfProperties().addAll(resource.getConnInstanceConfiguration());
+
+ resourceTO.setUsyncToken(resource.getSerializedUSyncToken());
+ resourceTO.setRsyncToken(resource.getSerializedRSyncToken());
+
+ resourceTO.getPropagationActionsClassNames().addAll(resource.getPropagationActionsClassNames());
+
+ return resourceTO;
+ }
+
+ private void populateMappingTO(final Mapping<?> mapping, final MappingTO mappingTO) {
+ mappingTO.setAccountLink(mapping.getAccountLink());
+
+ for (MappingItemTO itemTO : getMappingItemTOs(mapping.getItems())) {
+ if (itemTO.isAccountid()) {
+ mappingTO.setAccountIdItem(itemTO);
+ } else if (itemTO.isPassword()) {
+ mappingTO.setPasswordItem(itemTO);
+ } else {
+ mappingTO.addItem(itemTO);
+ }
+ }
+ }
+
+ private Set<MappingItemTO> getMappingItemTOs(final Collection<? extends MappingItem> items) {
+ Set<MappingItemTO> mappingTOs = new HashSet<>();
+ for (MappingItem item : items) {
+ LOG.debug("Asking for TO for {}", item);
+ mappingTOs.add(getMappingItemTO(item));
+ }
+
+ LOG.debug("Collected TOs: {}", mappingTOs);
+
+ return mappingTOs;
+ }
+
+ private MappingItemTO getMappingItemTO(final MappingItem item) {
+ if (item == null) {
+ LOG.error("Provided null mapping");
+
+ return null;
+ }
+
+ MappingItemTO itemTO = new MappingItemTO();
+
+ BeanUtils.copyProperties(item, itemTO, MAPPINGITEM_IGNORE_PROPERTIES);
+
+ itemTO.setKey(item.getKey());
+
+ LOG.debug("Obtained SchemaMappingTO {}", itemTO);
+
+ return itemTO;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/RoleDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/RoleDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/RoleDataBinder.java
new file mode 100644
index 0000000..d8dc0df
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/RoleDataBinder.java
@@ -0,0 +1,429 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.persistence.api.dao.EntitlementDAO;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.entity.AccountPolicy;
+import org.apache.syncope.persistence.api.entity.AttrTemplate;
+import org.apache.syncope.persistence.api.entity.Entitlement;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.persistence.api.entity.Schema;
+import org.apache.syncope.persistence.api.entity.membership.MDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MDerSchema;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MPlainSchema;
+import org.apache.syncope.persistence.api.entity.membership.MVirAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MVirSchema;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.api.entity.role.RDerAttr;
+import org.apache.syncope.persistence.api.entity.role.RDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.RDerSchema;
+import org.apache.syncope.persistence.api.entity.role.RPlainAttr;
+import org.apache.syncope.persistence.api.entity.role.RPlainAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.RPlainSchema;
+import org.apache.syncope.persistence.api.entity.role.RVirAttr;
+import org.apache.syncope.persistence.api.entity.role.RVirAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.RVirSchema;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.provisioning.api.propagation.PropagationByResource;
+import org.apache.syncope.server.utils.ConnObjectUtil;
+import org.apache.syncope.provisioning.api.WorkflowResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@Transactional(rollbackFor = { Throwable.class })
+public class RoleDataBinder extends AbstractAttributableDataBinder {
+
+ @Autowired
+ private RoleDAO roleDAO;
+
+ @Autowired
+ private ConnObjectUtil connObjectUtil;
+
+ @Autowired
+ private EntitlementDAO entitlementDAO;
+
+ @Transactional(readOnly = true)
+ public List<WorkflowResult<Long>> getUsersOnResourcesOnlyBecauseOfRole(final Long roleId) {
+ Role role = roleDAO.authFetchRole(roleId);
+
+ List<WorkflowResult<Long>> result = new ArrayList<WorkflowResult<Long>>();
+
+ for (Membership membership : roleDAO.findMemberships(role)) {
+ User user = membership.getUser();
+
+ PropagationByResource propByRes = new PropagationByResource();
+ for (ExternalResource resource : role.getResources()) {
+ if (!user.getOwnResources().contains(resource)) {
+ propByRes.add(ResourceOperation.DELETE, resource.getKey());
+ }
+
+ if (!propByRes.isEmpty()) {
+ result.add(new WorkflowResult<Long>(user.getKey(), propByRes, Collections.<String>emptySet()));
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private <T extends AttrTemplate<S>, S extends Schema> void setAttrTemplates(
+ final Role role, final List<String> schemaNames,
+ final Class<T> templateClass, final Class<S> schemaClass) {
+
+ List<T> toRemove = new ArrayList<T>();
+ for (T template : role.getAttrTemplates(templateClass)) {
+ if (!schemaNames.contains(template.getSchema().getKey())) {
+ toRemove.add(template);
+ }
+ }
+ role.getAttrTemplates(templateClass).removeAll(toRemove);
+
+ for (String schemaName : schemaNames) {
+ if (role.getAttrTemplate(templateClass, schemaName) == null) {
+ S schema = getSchema(schemaName, schemaClass);
+ if (schema != null) {
+ try {
+ T template = templateClass.newInstance();
+ template.setSchema(schema);
+ template.setOwner(role);
+ role.getAttrTemplates(templateClass).add(template);
+ } catch (Exception e) {
+ LOG.error("Could not create template for {}", templateClass, e);
+ }
+ }
+ }
+ }
+ }
+
+ public Role create(final Role role, final RoleTO roleTO) {
+ role.setInheritOwner(roleTO.isInheritOwner());
+
+ role.setInheritPlainAttrs(roleTO.isInheritAttrs());
+ role.setInheritDerAttrs(roleTO.isInheritDerAttrs());
+ role.setInheritVirAttrs(roleTO.isInheritVirAttrs());
+
+ role.setInheritTemplates(roleTO.isInheritTemplates());
+
+ role.setInheritPasswordPolicy(roleTO.isInheritPasswordPolicy());
+ role.setInheritAccountPolicy(roleTO.isInheritAccountPolicy());
+
+ SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+ // name and parent
+ SyncopeClientException invalidRoles = SyncopeClientException.build(ClientExceptionType.InvalidRoles);
+ if (roleTO.getName() == null) {
+ LOG.error("No name specified for this role");
+
+ invalidRoles.getElements().add("No name specified for this role");
+ } else {
+ role.setName(roleTO.getName());
+ }
+ Long parentRoleKey = null;
+ if (roleTO.getParent() != 0) {
+ Role parentRole = roleDAO.find(roleTO.getParent());
+ if (parentRole == null) {
+ LOG.error("Could not find role with id " + roleTO.getParent());
+
+ invalidRoles.getElements().add(String.valueOf(roleTO.getParent()));
+ scce.addException(invalidRoles);
+ } else {
+ role.setParent(parentRole);
+ parentRoleKey = role.getParent().getKey();
+ }
+ }
+
+ Role otherRole = roleDAO.find(roleTO.getName(), parentRoleKey);
+ if (otherRole != null) {
+ LOG.error("Another role exists with the same name " + "and the same parent role: " + otherRole);
+
+ invalidRoles.getElements().add(roleTO.getName());
+ }
+
+ // attribute templates
+ setAttrTemplates(role, roleTO.getRAttrTemplates(), RPlainAttrTemplate.class, RPlainSchema.class);
+ setAttrTemplates(role, roleTO.getRDerAttrTemplates(), RDerAttrTemplate.class, RDerSchema.class);
+ setAttrTemplates(role, roleTO.getRVirAttrTemplates(), RVirAttrTemplate.class, RVirSchema.class);
+ setAttrTemplates(role, roleTO.getMAttrTemplates(), MPlainAttrTemplate.class, MPlainSchema.class);
+ setAttrTemplates(role, roleTO.getMDerAttrTemplates(), MDerAttrTemplate.class, MDerSchema.class);
+ setAttrTemplates(role, roleTO.getMVirAttrTemplates(), MVirAttrTemplate.class, MVirSchema.class);
+
+ // attributes, derived attributes, virtual attributes and resources
+ fill(role, roleTO, attrUtilFactory.getInstance(AttributableType.ROLE), scce);
+
+ // entitlements
+ for (String entitlementName : roleTO.getEntitlements()) {
+ Entitlement entitlement = entitlementDAO.find(entitlementName);
+ if (entitlement == null) {
+ LOG.warn("Ignoring invalid entitlement {}", entitlementName);
+ } else {
+ role.addEntitlement(entitlement);
+ }
+ }
+
+ // owner
+ if (roleTO.getUserOwner() != null) {
+ User owner = userDAO.find(roleTO.getUserOwner());
+ if (owner == null) {
+ LOG.warn("Ignoring invalid user specified as owner: {}", roleTO.getUserOwner());
+ } else {
+ role.setUserOwner(owner);
+ }
+ }
+ if (roleTO.getRoleOwner() != null) {
+ Role owner = roleDAO.find(roleTO.getRoleOwner());
+ if (owner == null) {
+ LOG.warn("Ignoring invalid role specified as owner: {}", roleTO.getRoleOwner());
+ } else {
+ role.setRoleOwner(owner);
+ }
+ }
+
+ // policies
+ if (roleTO.getPasswordPolicy() != null) {
+ role.setPasswordPolicy((PasswordPolicy) policyDAO.find(roleTO.getPasswordPolicy()));
+ }
+ if (roleTO.getAccountPolicy() != null) {
+ role.setAccountPolicy((AccountPolicy) policyDAO.find(roleTO.getAccountPolicy()));
+ }
+
+ return role;
+ }
+
+ public PropagationByResource update(final Role role, final RoleMod roleMod) {
+ PropagationByResource propByRes = new PropagationByResource();
+
+ SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+ Set<String> currentResources = role.getResourceNames();
+
+ // name
+ SyncopeClientException invalidRoles = SyncopeClientException.build(ClientExceptionType.InvalidRoles);
+ if (roleMod.getName() != null) {
+ Role otherRole = roleDAO.find(roleMod.getName(),
+ role.getParent() == null ? null : role.getParent().getKey());
+ if (otherRole == null || role.equals(otherRole)) {
+ if (!roleMod.getName().equals(role.getName())) {
+ propByRes.addAll(ResourceOperation.UPDATE, currentResources);
+ for (String resource : currentResources) {
+ propByRes.addOldAccountId(resource, role.getName());
+ }
+
+ role.setName(roleMod.getName());
+ }
+ } else {
+ LOG.error("Another role exists with the same name and the same parent role: " + otherRole);
+
+ invalidRoles.getElements().add(roleMod.getName());
+ scce.addException(invalidRoles);
+ }
+ }
+
+ if (roleMod.getInheritOwner() != null) {
+ role.setInheritOwner(roleMod.getInheritOwner());
+ }
+
+ if (roleMod.getInheritTemplates() != null) {
+ role.setInheritTemplates(roleMod.getInheritTemplates());
+ }
+
+ if (roleMod.getInheritPlainAttrs() != null) {
+ role.setInheritPlainAttrs(roleMod.getInheritPlainAttrs());
+ }
+ if (roleMod.getInheritDerAttrs() != null) {
+ role.setInheritDerAttrs(roleMod.getInheritDerAttrs());
+ }
+ if (roleMod.getInheritVirAttrs() != null) {
+ role.setInheritVirAttrs(roleMod.getInheritVirAttrs());
+ }
+
+ if (roleMod.getInheritPasswordPolicy() != null) {
+ role.setInheritPasswordPolicy(roleMod.getInheritPasswordPolicy());
+ }
+ if (roleMod.getInheritAccountPolicy() != null) {
+ role.setInheritAccountPolicy(roleMod.getInheritAccountPolicy());
+ }
+
+ // entitlements
+ if (roleMod.isModEntitlements()) {
+ role.getEntitlements().clear();
+ for (String entitlementName : roleMod.getEntitlements()) {
+ Entitlement entitlement = entitlementDAO.find(entitlementName);
+ if (entitlement == null) {
+ LOG.warn("Ignoring invalid entitlement {}", entitlementName);
+ } else {
+ role.addEntitlement(entitlement);
+ }
+ }
+ }
+
+ // attribute templates
+ if (roleMod.isModRAttrTemplates()) {
+ setAttrTemplates(role, roleMod.getRPlainAttrTemplates(), RPlainAttrTemplate.class, RPlainSchema.class);
+ }
+ if (roleMod.isModRDerAttrTemplates()) {
+ setAttrTemplates(role, roleMod.getRDerAttrTemplates(), RDerAttrTemplate.class, RDerSchema.class);
+ }
+ if (roleMod.isModRVirAttrTemplates()) {
+ setAttrTemplates(role, roleMod.getRVirAttrTemplates(), RVirAttrTemplate.class, RVirSchema.class);
+ }
+ if (roleMod.isModMAttrTemplates()) {
+ setAttrTemplates(role, roleMod.getMPlainAttrTemplates(), MPlainAttrTemplate.class, MPlainSchema.class);
+ }
+ if (roleMod.isModMDerAttrTemplates()) {
+ setAttrTemplates(role, roleMod.getMDerAttrTemplates(), MDerAttrTemplate.class, MDerSchema.class);
+ }
+ if (roleMod.isModMVirAttrTemplates()) {
+ setAttrTemplates(role, roleMod.getMVirAttrTemplates(), MVirAttrTemplate.class, MVirSchema.class);
+ }
+
+ // policies
+ if (roleMod.getPasswordPolicy() != null) {
+ role.setPasswordPolicy(roleMod.getPasswordPolicy().getKey() == null
+ ? null
+ : (PasswordPolicy) policyDAO.find(roleMod.getPasswordPolicy().getKey()));
+ }
+ if (roleMod.getAccountPolicy() != null) {
+ role.setAccountPolicy(roleMod.getAccountPolicy().getKey() == null
+ ? null
+ : (AccountPolicy) policyDAO.find(roleMod.getAccountPolicy().getKey()));
+ }
+
+ // owner
+ if (roleMod.getUserOwner() != null) {
+ role.setUserOwner(roleMod.getUserOwner().getKey() == null
+ ? null
+ : userDAO.find(roleMod.getUserOwner().getKey()));
+ }
+ if (roleMod.getRoleOwner() != null) {
+ role.setRoleOwner(roleMod.getRoleOwner().getKey() == null
+ ? null
+ : roleDAO.find(roleMod.getRoleOwner().getKey()));
+ }
+
+ // attributes, derived attributes, virtual attributes and resources
+ propByRes.merge(fill(role, roleMod, attrUtilFactory.getInstance(AttributableType.ROLE), scce));
+
+ return propByRes;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Transactional(readOnly = true)
+ public RoleTO getRoleTO(final Role role) {
+ connObjectUtil.retrieveVirAttrValues(role, attrUtilFactory.getInstance(AttributableType.ROLE));
+
+ RoleTO roleTO = new RoleTO();
+
+ // set sys info
+ roleTO.setCreator(role.getCreator());
+ roleTO.setCreationDate(role.getCreationDate());
+ roleTO.setLastModifier(role.getLastModifier());
+ roleTO.setLastChangeDate(role.getLastChangeDate());
+
+ roleTO.setKey(role.getKey());
+ roleTO.setName(role.getName());
+
+ roleTO.setInheritOwner(role.isInheritOwner());
+
+ roleTO.setInheritTemplates(role.isInheritTemplates());
+
+ roleTO.setInheritAttrs(role.isInheritPlainAttrs());
+ roleTO.setInheritDerAttrs(role.isInheritDerAttrs());
+ roleTO.setInheritVirAttrs(role.isInheritVirAttrs());
+
+ roleTO.setInheritPasswordPolicy(role.isInheritPasswordPolicy());
+ roleTO.setInheritAccountPolicy(role.isInheritAccountPolicy());
+
+ if (role.getParent() != null) {
+ roleTO.setParent(role.getParent().getKey());
+ }
+
+ if (role.getUserOwner() != null) {
+ roleTO.setUserOwner(role.getUserOwner().getKey());
+ }
+ if (role.getRoleOwner() != null) {
+ roleTO.setRoleOwner(role.getRoleOwner().getKey());
+ }
+
+ // -------------------------
+ // Retrieve all [derived/virtual] attributes (inherited and not)
+ // -------------------------
+ final List<? extends RPlainAttr> allAttributes = role.findLastInheritedAncestorPlainAttrs();
+
+ final List<? extends RDerAttr> allDerAttributes = role.findLastInheritedAncestorDerAttrs();
+
+ final List<? extends RVirAttr> allVirAttributes = role.findLastInheritedAncestorVirAttrs();
+ // -------------------------
+
+ fillTO(roleTO, allAttributes, allDerAttributes, allVirAttributes, role.getResources());
+
+ for (Entitlement entitlement : role.getEntitlements()) {
+ roleTO.getEntitlements().add(entitlement.getKey());
+ }
+
+ for (RPlainAttrTemplate template : role.findInheritedTemplates(RPlainAttrTemplate.class)) {
+ roleTO.getRAttrTemplates().add(template.getSchema().getKey());
+ }
+ for (RDerAttrTemplate template : role.findInheritedTemplates(RDerAttrTemplate.class)) {
+ roleTO.getRDerAttrTemplates().add(template.getSchema().getKey());
+ }
+ for (RVirAttrTemplate template : role.findInheritedTemplates(RVirAttrTemplate.class)) {
+ roleTO.getRVirAttrTemplates().add(template.getSchema().getKey());
+ }
+ for (MPlainAttrTemplate template : role.findInheritedTemplates(MPlainAttrTemplate.class)) {
+ roleTO.getMAttrTemplates().add(template.getSchema().getKey());
+ }
+ for (MDerAttrTemplate template : role.findInheritedTemplates(MDerAttrTemplate.class)) {
+ roleTO.getMDerAttrTemplates().add(template.getSchema().getKey());
+ }
+ for (MVirAttrTemplate template : role.findInheritedTemplates(MVirAttrTemplate.class)) {
+ roleTO.getMVirAttrTemplates().add(template.getSchema().getKey());
+ }
+
+ roleTO.setPasswordPolicy(role.getPasswordPolicy() == null
+ ? null
+ : role.getPasswordPolicy().getKey());
+ roleTO.setAccountPolicy(role.getAccountPolicy() == null
+ ? null
+ : role.getAccountPolicy().getKey());
+
+ return roleTO;
+ }
+
+ @Transactional(readOnly = true)
+ public RoleTO getRoleTO(final Long key) {
+ return getRoleTO(roleDAO.authFetchRole(key));
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SchemaDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SchemaDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SchemaDataBinder.java
new file mode 100644
index 0000000..79cb4a5
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SchemaDataBinder.java
@@ -0,0 +1,163 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.DerSchemaTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.VirSchemaTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.persistence.api.entity.DerSchema;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+import org.apache.syncope.persistence.api.entity.PlainSchema;
+import org.apache.syncope.persistence.api.entity.VirSchema;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.apache.syncope.server.utils.jexl.JexlUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SchemaDataBinder {
+
+ @Autowired
+ private PlainSchemaDAO schemaDAO;
+
+ // --------------- PLAIN -----------------
+ private <T extends PlainSchema> void fill(final T schema, final PlainSchemaTO schemaTO) {
+ if (!JexlUtil.isExpressionValid(schemaTO.getMandatoryCondition())) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+ sce.getElements().add(schemaTO.getMandatoryCondition());
+ throw sce;
+ }
+
+ BeanUtils.copyProperties(schemaTO, schema);
+ }
+
+ public <T extends PlainSchema> void create(final PlainSchemaTO schemaTO, final T schema) {
+ fill(schema, schemaTO);
+ }
+
+ public <T extends PlainSchema> void update(final PlainSchemaTO schemaTO, final T schema,
+ final AttributableUtil attributableUtil) {
+
+ SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+ List<PlainAttr> attrs = schemaDAO.findAttrs(schema, attributableUtil.plainAttrClass());
+ if (!attrs.isEmpty()) {
+ if (schema.getType() != schemaTO.getType()) {
+ SyncopeClientException e = SyncopeClientException.build(
+ ClientExceptionType.valueOf("Invalid" + schema.getClass().getSimpleName()));
+ e.getElements().add("Cannot change type since " + schema.getKey() + " has attributes");
+
+ scce.addException(e);
+ }
+ if (schema.isUniqueConstraint() != schemaTO.isUniqueConstraint()) {
+ SyncopeClientException e = SyncopeClientException.build(ClientExceptionType.valueOf("Invalid"
+ + schema.getClass().getSimpleName()));
+ e.getElements().add("Cannot alter unique contraint since " + schema.getKey() + " has attributes");
+
+ scce.addException(e);
+ }
+ }
+
+ if (scce.hasExceptions()) {
+ throw scce;
+ }
+
+ fill(schema, schemaTO);
+ }
+
+ public <T extends PlainSchema> PlainSchemaTO getSchemaTO(
+ final T schema, final AttributableUtil attributableUtil) {
+
+ PlainSchemaTO schemaTO = new PlainSchemaTO();
+ BeanUtils.copyProperties(schema, schemaTO);
+
+ return schemaTO;
+ }
+
+ // --------------- DERIVED -----------------
+ private <T extends DerSchema> T populate(final T derSchema, final DerSchemaTO derSchemaTO) {
+ SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+ if (StringUtils.isBlank(derSchemaTO.getExpression())) {
+ SyncopeClientException requiredValuesMissing =
+ SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+ requiredValuesMissing.getElements().add("expression");
+
+ scce.addException(requiredValuesMissing);
+ } else if (!JexlUtil.isExpressionValid(derSchemaTO.getExpression())) {
+ SyncopeClientException invalidMandatoryCondition = SyncopeClientException.build(
+ ClientExceptionType.InvalidValues);
+ invalidMandatoryCondition.getElements().add(derSchemaTO.getExpression());
+
+ scce.addException(invalidMandatoryCondition);
+ }
+
+ if (scce.hasExceptions()) {
+ throw scce;
+ }
+
+ BeanUtils.copyProperties(derSchemaTO, derSchema);
+
+ return derSchema;
+ }
+
+ public <T extends DerSchema> T create(final DerSchemaTO derSchemaTO, final T derSchema) {
+ return populate(derSchema, derSchemaTO);
+ }
+
+ public <T extends DerSchema> T update(final DerSchemaTO derSchemaTO, final T derSchema) {
+ return populate(derSchema, derSchemaTO);
+ }
+
+ public <T extends DerSchema> DerSchemaTO getDerSchemaTO(final T derSchema) {
+ DerSchemaTO derSchemaTO = new DerSchemaTO();
+ BeanUtils.copyProperties(derSchema, derSchemaTO);
+
+ return derSchemaTO;
+ }
+
+ // --------------- VIRTUAL -----------------
+ private <T extends VirSchema> T fill(final T virSchema, final VirSchemaTO virSchemaTO) {
+ BeanUtils.copyProperties(virSchemaTO, virSchema);
+
+ return virSchema;
+ }
+
+ public <T extends VirSchema> T create(final VirSchemaTO virSchemaTO, final T virSchema) {
+ return fill(virSchema, virSchemaTO);
+ }
+
+ public <T extends VirSchema> T update(final VirSchemaTO virSchemaTO, final T virSchema) {
+ return fill(virSchema, virSchemaTO);
+ }
+
+ public <T extends VirSchema> VirSchemaTO getVirSchemaTO(final T virSchema) {
+ VirSchemaTO virSchemaTO = new VirSchemaTO();
+ BeanUtils.copyProperties(virSchema, virSchemaTO);
+
+ return virSchemaTO;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SecurityQuestionDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SecurityQuestionDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SecurityQuestionDataBinder.java
new file mode 100644
index 0000000..b8dce1d
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/SecurityQuestionDataBinder.java
@@ -0,0 +1,51 @@
+/*
+ * 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.server.logic.data;
+
+import org.apache.syncope.common.lib.to.SecurityQuestionTO;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.user.SecurityQuestion;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SecurityQuestionDataBinder {
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ public SecurityQuestionTO getSecurityQuestionTO(final SecurityQuestion securityQuestion) {
+ SecurityQuestionTO securityQuestionTO = new SecurityQuestionTO();
+
+ BeanUtils.copyProperties(securityQuestion, securityQuestionTO);
+
+ return securityQuestionTO;
+ }
+
+ public SecurityQuestion create(final SecurityQuestionTO securityQuestionTO) {
+ SecurityQuestion result = entityFactory.newEntity(SecurityQuestion.class);
+ update(result, securityQuestionTO);
+ return result;
+ }
+
+ public void update(final SecurityQuestion securityQuestion, final SecurityQuestionTO securityQuestionTO) {
+ BeanUtils.copyProperties(securityQuestionTO, securityQuestion, "key");
+ }
+}
[02/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationTaskExecutor.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationTaskExecutor.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationTaskExecutor.java
new file mode 100644
index 0000000..1b37718
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationTaskExecutor.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.provisioning.api.propagation;
+
+import java.util.Collection;
+import org.apache.syncope.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.persistence.api.entity.task.TaskExec;
+
+/**
+ * Execute propagation tasks.
+ *
+ * @see PropagationTask
+ */
+public interface PropagationTaskExecutor {
+
+ /**
+ * Name for special propagation attribute used to indicate whether there are attributes, marked as mandatory in the
+ * mapping but not to be propagated.
+ */
+ String MANDATORY_MISSING_ATTR_NAME = "__MANDATORY_MISSING__";
+
+ /**
+ * Name for special propagation attribute used to indicate whether there are attributes, marked as mandatory in the
+ * mapping but about to be propagated as null or empty.
+ */
+ String MANDATORY_NULL_OR_EMPTY_ATTR_NAME = "__MANDATORY_NULL_OR_EMPTY__";
+
+ /**
+ * Execute the given PropagationTask and returns the generated TaskExec.
+ *
+ * @param task to be executed
+ * @return the generated TaskExec
+ */
+ TaskExec execute(PropagationTask task);
+
+ /**
+ * Execute the given PropagationTask, invoke the given handler and returns the generated TaskExec.
+ *
+ * @param task to be executed
+ * @param reporter to report propagation execution status
+ * @return the generated TaskExec
+ */
+ TaskExec execute(PropagationTask task, PropagationReporter reporter);
+
+ /**
+ * Execute a collection of PropagationTask objects.
+ * The process is interrupted as soon as the result of the communication with a primary resource is in error.
+ *
+ * @param tasks to be executed
+ */
+ void execute(Collection<PropagationTask> tasks);
+
+ /**
+ * Execute a collection of PropagationTask objects and invoke the given handler on each of these.
+ * The process is interrupted as soon as the result of the communication with a primary resource is in error.
+ *
+ * @param tasks to be execute, in given order
+ * @param reporter to report propagation execution status
+ */
+ void execute(Collection<PropagationTask> tasks, PropagationReporter reporter);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/sync/SyncCorrelationRule.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/sync/SyncCorrelationRule.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/sync/SyncCorrelationRule.java
new file mode 100644
index 0000000..4056e74
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/sync/SyncCorrelationRule.java
@@ -0,0 +1,36 @@
+/*
+ * 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.provisioning.api.sync;
+
+import org.apache.syncope.persistence.api.dao.search.SearchCond;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+
+/**
+ * Interface for correlation rule to be evaluated during SyncJob execution.
+ */
+public interface SyncCorrelationRule {
+
+ /**
+ * Return a search condition.
+ *
+ * @param connObj connector object.
+ * @return search condition.
+ */
+ SearchCond getSearchCond(ConnectorObject connObj);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-common/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-common/pom.xml b/syncope620/server/provisioning-common/pom.xml
new file mode 100644
index 0000000..d920258
--- /dev/null
+++ b/syncope620/server/provisioning-common/pom.xml
@@ -0,0 +1,44 @@
+<?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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.syncope</groupId>
+ <artifactId>syncope-server</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </parent>
+
+ <name>Apache Syncope Server Provisioning Common</name>
+ <description>Apache Syncope Server Provisioning Common</description>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-provisioning-common</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-provisioning-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-common/src/main/java/org/apache/syncope/provisioning/common/cache/DisabledVirAttrCache.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-common/src/main/java/org/apache/syncope/provisioning/common/cache/DisabledVirAttrCache.java b/syncope620/server/provisioning-common/src/main/java/org/apache/syncope/provisioning/common/cache/DisabledVirAttrCache.java
new file mode 100644
index 0000000..3491075
--- /dev/null
+++ b/syncope620/server/provisioning-common/src/main/java/org/apache/syncope/provisioning/common/cache/DisabledVirAttrCache.java
@@ -0,0 +1,52 @@
+/*
+ * 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.provisioning.common.cache;
+
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.provisioning.api.cache.VirAttrCache;
+import org.apache.syncope.provisioning.api.cache.VirAttrCacheValue;
+
+/**
+ * Empty virtual attribute value cache implementation.
+ */
+public class DisabledVirAttrCache implements VirAttrCache {
+
+ @Override
+ public void expire(final AttributableType type, final Long id, final String schemaName) {
+ // nothing to do
+ }
+
+ @Override
+ public VirAttrCacheValue get(final AttributableType type, final Long id, final String schemaName) {
+ return null;
+ }
+
+ @Override
+ public boolean isValidEntry(VirAttrCacheValue value) {
+ return false;
+ }
+
+ @Override
+ public void put(
+ final AttributableType type, final Long id, final String schemaName, final VirAttrCacheValue value) {
+
+ // nothing to do
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-common/src/main/java/org/apache/syncope/provisioning/common/cache/MemoryVirAttrCache.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-common/src/main/java/org/apache/syncope/provisioning/common/cache/MemoryVirAttrCache.java b/syncope620/server/provisioning-common/src/main/java/org/apache/syncope/provisioning/common/cache/MemoryVirAttrCache.java
new file mode 100644
index 0000000..0199499
--- /dev/null
+++ b/syncope620/server/provisioning-common/src/main/java/org/apache/syncope/provisioning/common/cache/MemoryVirAttrCache.java
@@ -0,0 +1,151 @@
+/*
+ * 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.provisioning.common.cache;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.provisioning.api.cache.VirAttrCache;
+import org.apache.syncope.provisioning.api.cache.VirAttrCacheKey;
+import org.apache.syncope.provisioning.api.cache.VirAttrCacheValue;
+
+/**
+ * In-memory (HashMap) virtual attribute value cache implementation.
+ */
+public class MemoryVirAttrCache implements VirAttrCache {
+
+ /**
+ * Elapsed time in seconds.
+ */
+ protected int ttl;
+
+ /**
+ * Max cache size.
+ */
+ protected int maxCacheSize;
+
+ /**
+ * Cache entries.
+ */
+ protected final Map<VirAttrCacheKey, VirAttrCacheValue> cache = new HashMap<VirAttrCacheKey, VirAttrCacheValue>();
+
+ public MemoryVirAttrCache(final int ttl, final int maxCacheSize) {
+ this.ttl = ttl;
+ this.maxCacheSize = maxCacheSize;
+ }
+
+ /**
+ * Cache virtual attribute values.
+ *
+ * @param type user or role
+ * @param id user or role id
+ * @param schemaName virtual attribute name
+ * @param value virtual attribute values
+ */
+ @Override
+ public void put(
+ final AttributableType type,
+ final Long id,
+ final String schemaName,
+ final VirAttrCacheValue value) {
+
+ synchronized (cache) {
+ // this operations (retrieve cache space and put entry on) have to be thread safe.
+ if (this.cache.size() >= this.maxCacheSize) {
+ free();
+ }
+
+ cache.put(new VirAttrCacheKey(type, id, schemaName), value);
+ }
+ }
+
+ /**
+ * Retrieve cached value. Return null in case of virtual attribute not cached.
+ *
+ * @param type user or role
+ * @param id user or role id
+ * @param schemaName virtual attribute schema name.
+ * @return cached values or null if virtual attribute is not cached.
+ */
+ @Override
+ public VirAttrCacheValue get(final AttributableType type, final Long id, final String schemaName) {
+ return cache.get(new VirAttrCacheKey(type, id, schemaName));
+ }
+
+ /**
+ * Force entry expiring.
+ *
+ * @param type user or role
+ * @param id user or role id
+ * @param schemaName virtual attribute schema name
+ */
+ @Override
+ public void expire(final AttributableType type, final Long id, final String schemaName) {
+ final VirAttrCacheValue value = cache.get(new VirAttrCacheKey(type, id, schemaName));
+ if (isValidEntry(value)) {
+ synchronized (cache) {
+ value.forceExpiring();
+ }
+ }
+ }
+
+ /**
+ * Remove expired entries if exist. If required, one entry at least (the latest recently used) will be taken off.
+ * This method is not thread safe: the caller have to take care to synchronize the call.
+ */
+ private void free() {
+ final Set<VirAttrCacheKey> toBeRemoved = new HashSet<VirAttrCacheKey>();
+
+ Map.Entry<VirAttrCacheKey, VirAttrCacheValue> latest = null;
+
+ for (Map.Entry<VirAttrCacheKey, VirAttrCacheValue> entry : cache.entrySet()) {
+ if (isValidEntry(entry.getValue())) {
+ final Date date = entry.getValue().getLastAccessDate();
+ if (latest == null || latest.getValue().getLastAccessDate().after(date)) {
+ latest = entry;
+ }
+ } else {
+ toBeRemoved.add(entry.getKey());
+ }
+ }
+
+ if (toBeRemoved.isEmpty() && latest != null) {
+ // remove the oldest entry
+ cache.remove(latest.getKey());
+ } else {
+ // remove expired entries
+ cache.keySet().removeAll(toBeRemoved);
+ }
+ }
+
+ /**
+ * Cache entry is valid if and only if value exist and it is not expired.
+ *
+ * @param value cache entry value.
+ * @return TRUE if the value is valid; FALSE otherwise.
+ */
+ @Override
+ public boolean isValidEntry(final VirAttrCacheValue value) {
+ final Date expiringDate = new Date(value == null ? 0 : value.getCreationDate().getTime() + ttl * 1000);
+ return expiringDate.after(new Date());
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/security/src/main/java/org/apache/syncope/server/security/SecureRandomUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/security/src/main/java/org/apache/syncope/server/security/SecureRandomUtil.java b/syncope620/server/security/src/main/java/org/apache/syncope/server/security/SecureRandomUtil.java
deleted file mode 100644
index 3f2735a..0000000
--- a/syncope620/server/security/src/main/java/org/apache/syncope/server/security/SecureRandomUtil.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.server.security;
-
-import java.security.SecureRandom;
-
-import org.apache.commons.lang3.RandomStringUtils;
-
-public class SecureRandomUtil {
-
- private static final SecureRandom RANDOM = new SecureRandom();
-
- public static String generateRandomPassword(final int tokenLength) {
- return RandomStringUtils.random(tokenLength, 0, 0, true, false, null, RANDOM);
- }
-
- public static String generateRandomLetter() {
- return RandomStringUtils.random(1, 0, 0, true, false, null, RANDOM);
- }
-
- public static String generateRandomNumber() {
- return RandomStringUtils.random(1, 0, 0, false, true, null, RANDOM);
- }
-
- public static String generateRandomSpecialCharacter(char[] characters) {
- return RandomStringUtils.random(1, 0, 0, false, false, characters, RANDOM);
- }
-}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/security/src/main/java/org/apache/syncope/server/security/UnauthorizedRoleException.java
----------------------------------------------------------------------
diff --git a/syncope620/server/security/src/main/java/org/apache/syncope/server/security/UnauthorizedRoleException.java b/syncope620/server/security/src/main/java/org/apache/syncope/server/security/UnauthorizedRoleException.java
new file mode 100644
index 0000000..6586ccc
--- /dev/null
+++ b/syncope620/server/security/src/main/java/org/apache/syncope/server/security/UnauthorizedRoleException.java
@@ -0,0 +1,42 @@
+/*
+ * 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.server.security;
+
+import java.util.Collections;
+import java.util.Set;
+
+public class UnauthorizedRoleException extends RuntimeException {
+
+ private static final long serialVersionUID = 7540587364235915081L;
+
+ private final Set<Long> roleIds;
+
+ public UnauthorizedRoleException(final Set<Long> roleIds) {
+ super("Missing entitlement for role(s) " + roleIds);
+ this.roleIds = roleIds;
+ }
+
+ public UnauthorizedRoleException(final Long roleId) {
+ this(Collections.singleton(roleId));
+ }
+
+ public Set<Long> getRoleIds() {
+ return roleIds;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/utils/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/utils/pom.xml b/syncope620/server/utils/pom.xml
index af4a55e..4e9fb6f 100644
--- a/syncope620/server/utils/pom.xml
+++ b/syncope620/server/utils/pom.xml
@@ -62,7 +62,7 @@ under the License.
<dependency>
<groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
+ <artifactId>spring-tx</artifactId>
</dependency>
<dependency>
@@ -70,6 +70,21 @@ under the License.
<artifactId>syncope-persistence-api</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-provisioning-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-server-security</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-server-spring</artifactId>
+ <version>${project.version}</version>
+ </dependency>
</dependencies>
</project>
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/ConnObjectUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/ConnObjectUtil.java b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/ConnObjectUtil.java
new file mode 100644
index 0000000..d2afd35
--- /dev/null
+++ b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/ConnObjectUtil.java
@@ -0,0 +1,764 @@
+/*
+ * 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.server.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.AttributableOperations;
+import org.apache.syncope.common.lib.mod.AbstractAttributableMod;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.common.lib.types.PasswordPolicySpec;
+import org.apache.syncope.persistence.api.attrvalue.validation.ParsingValidationException;
+import org.apache.syncope.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.persistence.api.dao.PolicyDAO;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.dao.UserDAO;
+import org.apache.syncope.persistence.api.entity.Attributable;
+import org.apache.syncope.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.MappingItem;
+import org.apache.syncope.persistence.api.entity.PasswordPolicy;
+import org.apache.syncope.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.persistence.api.entity.PlainSchema;
+import org.apache.syncope.persistence.api.entity.Subject;
+import org.apache.syncope.persistence.api.entity.VirAttr;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.task.SyncTask;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.provisioning.api.Connector;
+import org.apache.syncope.provisioning.api.ConnectorFactory;
+import org.apache.syncope.provisioning.api.cache.VirAttrCache;
+import org.apache.syncope.provisioning.api.cache.VirAttrCacheValue;
+import org.apache.syncope.server.security.Encryptor;
+import org.apache.syncope.server.security.UnauthorizedRoleException;
+import org.apache.syncope.server.spring.ApplicationContextProvider;
+import org.apache.syncope.server.utils.jexl.JexlUtil;
+import org.identityconnectors.common.Base64;
+import org.identityconnectors.common.security.GuardedByteArray;
+import org.identityconnectors.common.security.GuardedString;
+import org.identityconnectors.framework.common.objects.Attribute;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+import org.identityconnectors.framework.common.objects.ObjectClass;
+import org.identityconnectors.framework.common.objects.OperationOptions;
+import org.identityconnectors.framework.common.objects.Uid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class ConnObjectUtil {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(ConnObjectUtil.class);
+
+ @Autowired
+ private PolicyDAO policyDAO;
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @Autowired
+ private RoleDAO roleDAO;
+
+ @Autowired
+ private ExternalResourceDAO resourceDAO;
+
+ @Autowired
+ private PlainSchemaDAO plainSchemaDAO;
+
+ @Autowired
+ private PasswordGenerator pwdGen;
+
+ private final Encryptor encryptor = Encryptor.getInstance();
+
+ /**
+ * Virtual attribute cache.
+ */
+ @Autowired
+ private VirAttrCache virAttrCache;
+
+ public ObjectClass fromSubject(final Subject<?, ?, ?> subject) {
+ if (subject == null) {
+ throw new IllegalArgumentException("No ObjectClass could be provided for " + subject);
+ }
+
+ ObjectClass result = null;
+ if (subject instanceof User) {
+ result = ObjectClass.ACCOUNT;
+ }
+ if (subject instanceof Role) {
+ result = ObjectClass.GROUP;
+ }
+
+ return result;
+ }
+
+ /**
+ * Build a UserTO / RoleTO out of connector object attributes and schema mapping.
+ *
+ * @param obj connector object
+ * @param syncTask synchronization task
+ * @param attrUtil AttributableUtil
+ * @param <T> user/role
+ * @return UserTO for the user to be created
+ */
+ @Transactional(readOnly = true)
+ public <T extends AbstractSubjectTO> T getSubjectTO(final ConnectorObject obj, final SyncTask syncTask,
+ final AttributableUtil attrUtil) {
+
+ T subjectTO = getSubjectTOFromConnObject(obj, syncTask, attrUtil);
+
+ // (for users) if password was not set above, generate
+ if (subjectTO instanceof UserTO && StringUtils.isBlank(((UserTO) subjectTO).getPassword())) {
+ final UserTO userTO = (UserTO) subjectTO;
+
+ List<PasswordPolicySpec> ppSpecs = new ArrayList<>();
+
+ PasswordPolicy globalPP = policyDAO.getGlobalPasswordPolicy();
+ if (globalPP != null && globalPP.getSpecification(PasswordPolicySpec.class) != null) {
+ ppSpecs.add(globalPP.getSpecification(PasswordPolicySpec.class));
+ }
+
+ for (MembershipTO memb : userTO.getMemberships()) {
+ Role role = roleDAO.find(memb.getRoleId());
+ if (role != null && role.getPasswordPolicy() != null
+ && role.getPasswordPolicy().getSpecification(PasswordPolicySpec.class) != null) {
+
+ ppSpecs.add(role.getPasswordPolicy().getSpecification(PasswordPolicySpec.class));
+ }
+ }
+
+ for (String resName : userTO.getResources()) {
+ ExternalResource resource = resourceDAO.find(resName);
+ if (resource != null && resource.getPasswordPolicy() != null
+ && resource.getPasswordPolicy().getSpecification(PasswordPolicySpec.class) != null) {
+
+ ppSpecs.add(resource.getPasswordPolicy().getSpecification(PasswordPolicySpec.class));
+ }
+ }
+
+ String password;
+ try {
+ password = pwdGen.generate(ppSpecs);
+ } catch (InvalidPasswordPolicySpecException e) {
+ LOG.error("Could not generate policy-compliant random password for {}", userTO, e);
+
+ password = SecureRandomUtil.generateRandomPassword(16);
+ }
+ userTO.setPassword(password);
+ }
+
+ return subjectTO;
+ }
+
+ /**
+ * Build an UserMod out of connector object attributes and schema mapping.
+ *
+ * @param key user to be updated
+ * @param obj connector object
+ * @param original subject to get diff from
+ * @param syncTask synchronization task
+ * @param attrUtil AttributableUtil
+ * @param <T> user/role
+ * @return modifications for the user/role to be updated
+ * @throws NotFoundException if given id does not correspond to a T instance
+ * @throws UnauthorizedRoleException if there are no enough entitlements to access the T instance
+ */
+ @SuppressWarnings("unchecked")
+ @Transactional(readOnly = true)
+ public <T extends AbstractAttributableMod> T getAttributableMod(final Long key, final ConnectorObject obj,
+ final AbstractAttributableTO original, final SyncTask syncTask, final AttributableUtil attrUtil)
+ throws NotFoundException, UnauthorizedRoleException {
+
+ final AbstractAttributableTO updated = getSubjectTOFromConnObject(obj, syncTask, attrUtil);
+ updated.setKey(key);
+
+ if (AttributableType.USER == attrUtil.getType()) {
+ // update password if and only if password is really changed
+ final User user = userDAO.authFecthUser(key);
+ if (StringUtils.isBlank(((UserTO) updated).getPassword())
+ || encryptor.verify(((UserTO) updated).getPassword(),
+ user.getCipherAlgorithm(), user.getPassword())) {
+
+ ((UserTO) updated).setPassword(null);
+ }
+
+ for (MembershipTO membTO : ((UserTO) updated).getMemberships()) {
+ Membership memb = user.getMembership(membTO.getRoleId());
+ if (memb != null) {
+ membTO.setKey(memb.getKey());
+ }
+ }
+
+ return (T) AttributableOperations.diff(((UserTO) updated), ((UserTO) original), true);
+ }
+ if (AttributableType.ROLE == attrUtil.getType()) {
+ // reading from connector object cannot change entitlements
+ ((RoleTO) updated).getEntitlements().addAll(((RoleTO) original).getEntitlements());
+ return (T) AttributableOperations.diff(((RoleTO) updated), ((RoleTO) original), true);
+ }
+
+ return null;
+ }
+
+ private <T extends AbstractSubjectTO> T getSubjectTOFromConnObject(final ConnectorObject obj,
+ final SyncTask syncTask, final AttributableUtil attrUtil) {
+
+ final T subjectTO = attrUtil.newSubjectTO();
+
+ // 1. fill with data from connector object
+ for (MappingItem item : attrUtil.getUidToMappingItems(
+ syncTask.getResource(), MappingPurpose.SYNCHRONIZATION)) {
+
+ Attribute attribute = obj.getAttributeByName(item.getExtAttrName());
+
+ AttrTO attributeTO;
+ switch (item.getIntMappingType()) {
+ case UserId:
+ case RoleId:
+ break;
+
+ case Password:
+ if (subjectTO instanceof UserTO && attribute != null && attribute.getValue() != null
+ && !attribute.getValue().isEmpty()) {
+
+ ((UserTO) subjectTO).setPassword(getPassword(attribute.getValue().get(0)));
+ }
+ break;
+
+ case Username:
+ if (subjectTO instanceof UserTO) {
+ ((UserTO) subjectTO).setUsername(attribute == null || attribute.getValue().isEmpty()
+ || attribute.getValue().get(0) == null
+ ? null
+ : attribute.getValue().get(0).toString());
+ }
+ break;
+
+ case RoleName:
+ if (subjectTO instanceof RoleTO) {
+ ((RoleTO) subjectTO).setName(attribute == null || attribute.getValue().isEmpty()
+ || attribute.getValue().get(0) == null
+ ? null
+ : attribute.getValue().get(0).toString());
+ }
+ break;
+
+ case RoleOwnerSchema:
+ if (subjectTO instanceof RoleTO && attribute != null) {
+ // using a special attribute (with schema "", that will be ignored) for carrying the
+ // RoleOwnerSchema value
+ attributeTO = new AttrTO();
+ attributeTO.setSchema(StringUtils.EMPTY);
+ if (attribute.getValue().isEmpty() || attribute.getValue().get(0) == null) {
+ attributeTO.getValues().add(StringUtils.EMPTY);
+ } else {
+ attributeTO.getValues().add(attribute.getValue().get(0).toString());
+ }
+
+ ((RoleTO) subjectTO).getPlainAttrs().add(attributeTO);
+ }
+ break;
+
+ case UserSchema:
+ case RoleSchema:
+ attributeTO = new AttrTO();
+ attributeTO.setSchema(item.getIntAttrName());
+
+ PlainSchema schema = plainSchemaDAO.find(item.getIntAttrName(), attrUtil.plainSchemaClass());
+
+ for (Object value : attribute == null || attribute.getValue() == null
+ ? Collections.emptyList()
+ : attribute.getValue()) {
+
+ AttrSchemaType schemaType = schema == null ? AttrSchemaType.String : schema.getType();
+ if (value != null) {
+ final PlainAttrValue attrValue = attrUtil.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;
+ }
+ }
+ attributeTO.getValues().add(attrValue.getValueAsString(schemaType));
+ }
+ }
+
+ subjectTO.getPlainAttrs().add(attributeTO);
+ break;
+
+ case UserDerivedSchema:
+ case RoleDerivedSchema:
+ attributeTO = new AttrTO();
+ attributeTO.setSchema(item.getIntAttrName());
+ subjectTO.getDerAttrs().add(attributeTO);
+ break;
+
+ case UserVirtualSchema:
+ case RoleVirtualSchema:
+ attributeTO = new AttrTO();
+ attributeTO.setSchema(item.getIntAttrName());
+
+ for (Object value : attribute == null || attribute.getValue() == null
+ ? Collections.emptyList()
+ : attribute.getValue()) {
+
+ if (value != null) {
+ attributeTO.getValues().add(value.toString());
+ }
+ }
+
+ subjectTO.getVirAttrs().add(attributeTO);
+ break;
+
+ default:
+ }
+ }
+
+ // 2. add data from defined template (if any)
+ AbstractSubjectTO template = AttributableType.USER == attrUtil.getType()
+ ? syncTask.getUserTemplate() : syncTask.getRoleTemplate();
+
+ if (template != null) {
+ if (template instanceof UserTO) {
+ if (StringUtils.isNotBlank(((UserTO) template).getUsername())) {
+ String evaluated = JexlUtil.evaluate(((UserTO) template).getUsername(), subjectTO);
+ if (StringUtils.isNotBlank(evaluated)) {
+ ((UserTO) subjectTO).setUsername(evaluated);
+ }
+ }
+
+ if (StringUtils.isNotBlank(((UserTO) template).getPassword())) {
+ String evaluated = JexlUtil.evaluate(((UserTO) template).getPassword(), subjectTO);
+ if (StringUtils.isNotBlank(evaluated)) {
+ ((UserTO) subjectTO).setPassword(evaluated);
+ }
+ }
+
+ Map<Long, MembershipTO> currentMembs = ((UserTO) subjectTO).getMembershipMap();
+ for (MembershipTO membTO : ((UserTO) template).getMemberships()) {
+ MembershipTO membTBU;
+ if (currentMembs.containsKey(membTO.getRoleId())) {
+ membTBU = currentMembs.get(membTO.getRoleId());
+ } else {
+ membTBU = new MembershipTO();
+ membTBU.setRoleId(membTO.getRoleId());
+ ((UserTO) subjectTO).getMemberships().add(membTBU);
+ }
+ fillFromTemplate(membTBU, membTO);
+ }
+ }
+ if (template instanceof RoleTO) {
+ if (StringUtils.isNotBlank(((RoleTO) template).getName())) {
+ String evaluated = JexlUtil.evaluate(((RoleTO) template).getName(), subjectTO);
+ if (StringUtils.isNotBlank(evaluated)) {
+ ((RoleTO) subjectTO).setName(evaluated);
+ }
+ }
+
+ if (((RoleTO) template).getParent() != 0) {
+ final Role parentRole = roleDAO.find(((RoleTO) template).getParent());
+ if (parentRole != null) {
+ ((RoleTO) subjectTO).setParent(parentRole.getKey());
+ }
+ }
+
+ if (((RoleTO) template).getUserOwner() != null) {
+ final User userOwner = userDAO.find(((RoleTO) template).getUserOwner());
+ if (userOwner != null) {
+ ((RoleTO) subjectTO).setUserOwner(userOwner.getKey());
+ }
+ }
+ if (((RoleTO) template).getRoleOwner() != null) {
+ final Role roleOwner = roleDAO.find(((RoleTO) template).getRoleOwner());
+ if (roleOwner != null) {
+ ((RoleTO) subjectTO).setRoleOwner(roleOwner.getKey());
+ }
+ }
+
+ ((RoleTO) subjectTO).getEntitlements().addAll(((RoleTO) template).getEntitlements());
+
+ ((RoleTO) subjectTO).getRAttrTemplates().addAll(((RoleTO) template).getRAttrTemplates());
+ ((RoleTO) subjectTO).getRDerAttrTemplates().addAll(((RoleTO) template).getRDerAttrTemplates());
+ ((RoleTO) subjectTO).getRVirAttrTemplates().addAll(((RoleTO) template).getRVirAttrTemplates());
+ ((RoleTO) subjectTO).getMAttrTemplates().addAll(((RoleTO) template).getMAttrTemplates());
+ ((RoleTO) subjectTO).getMDerAttrTemplates().addAll(((RoleTO) template).getMDerAttrTemplates());
+ ((RoleTO) subjectTO).getMVirAttrTemplates().addAll(((RoleTO) template).getMVirAttrTemplates());
+
+ ((RoleTO) subjectTO).setAccountPolicy(((RoleTO) template).getAccountPolicy());
+ ((RoleTO) subjectTO).setPasswordPolicy(((RoleTO) template).getPasswordPolicy());
+
+ ((RoleTO) subjectTO).setInheritOwner(((RoleTO) template).isInheritOwner());
+ ((RoleTO) subjectTO).setInheritTemplates(((RoleTO) template).isInheritTemplates());
+ ((RoleTO) subjectTO).setInheritAttrs(((RoleTO) template).isInheritAttrs());
+ ((RoleTO) subjectTO).setInheritDerAttrs(((RoleTO) template).isInheritDerAttrs());
+ ((RoleTO) subjectTO).setInheritVirAttrs(((RoleTO) template).isInheritVirAttrs());
+ ((RoleTO) subjectTO).setInheritPasswordPolicy(((RoleTO) template).isInheritPasswordPolicy());
+ ((RoleTO) subjectTO).setInheritAccountPolicy(((RoleTO) template).isInheritAccountPolicy());
+ }
+
+ fillFromTemplate(subjectTO, template);
+
+ for (String resource : template.getResources()) {
+ subjectTO.getResources().add(resource);
+ }
+ }
+
+ return subjectTO;
+ }
+
+ /**
+ * Extract password value from passed value (if instance of GuardedString or GuardedByteArray).
+ *
+ * @param pwd received from the underlying connector
+ * @return password value
+ */
+ public String getPassword(final Object pwd) {
+ final StringBuilder result = new StringBuilder();
+
+ if (pwd instanceof GuardedString) {
+ ((GuardedString) pwd).access(new GuardedString.Accessor() {
+
+ @Override
+ public void access(final char[] clearChars) {
+ result.append(clearChars);
+ }
+ });
+ } else if (pwd instanceof GuardedByteArray) {
+ ((GuardedByteArray) pwd).access(new GuardedByteArray.Accessor() {
+
+ @Override
+ public void access(final byte[] clearBytes) {
+ result.append(new String(clearBytes));
+ }
+ });
+ } else if (pwd instanceof String) {
+ result.append((String) pwd);
+ } else {
+ result.append(pwd.toString());
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Get connector object TO from a connector object.
+ *
+ * @param connObject connector object.
+ * @return connector object TO.
+ */
+ public ConnObjectTO getConnObjectTO(final ConnectorObject connObject) {
+ final ConnObjectTO connObjectTO = new ConnObjectTO();
+
+ for (Attribute attr : connObject.getAttributes()) {
+ AttrTO attrTO = new AttrTO();
+ attrTO.setSchema(attr.getName());
+
+ if (attr.getValue() != null) {
+ for (Object value : attr.getValue()) {
+ if (value != null) {
+ if (value instanceof GuardedString || value instanceof GuardedByteArray) {
+ attrTO.getValues().add(getPassword(value));
+ } else if (value instanceof byte[]) {
+ attrTO.getValues().add(Base64.encode((byte[]) value));
+ } else {
+ attrTO.getValues().add(value.toString());
+ }
+ }
+ }
+ }
+
+ connObjectTO.getPlainAttrs().add(attrTO);
+ }
+
+ return connObjectTO;
+ }
+
+ /**
+ * Query connected external resources for values to populated virtual attributes associated with the given owner.
+ *
+ * @param owner user or role
+ * @param attrUtil attributable util
+ */
+ public void retrieveVirAttrValues(final Attributable<?, ?, ?> owner, final AttributableUtil attrUtil) {
+ final ConfigurableApplicationContext context = ApplicationContextProvider.getApplicationContext();
+ final ConnectorFactory connFactory = context.getBean(ConnectorFactory.class);
+
+ final IntMappingType type = attrUtil.getType() == AttributableType.USER
+ ? IntMappingType.UserVirtualSchema : attrUtil.getType() == AttributableType.ROLE
+ ? IntMappingType.RoleVirtualSchema : IntMappingType.MembershipVirtualSchema;
+
+ final Map<String, ConnectorObject> externalResources = new HashMap<>();
+
+ // -----------------------
+ // Retrieve virtual attribute values if and only if they have not been retrieved yet
+ // -----------------------
+ for (VirAttr virAttr : owner.getVirAttrs()) {
+ // reset value set
+ if (virAttr.getValues().isEmpty()) {
+ retrieveVirAttrValue(owner, virAttr, attrUtil, type, externalResources, connFactory);
+ }
+ }
+ // -----------------------
+ }
+
+ private void retrieveVirAttrValue(
+ final Attributable<?, ?, ?> owner,
+ final VirAttr virAttr,
+ final AttributableUtil attrUtil,
+ final IntMappingType type,
+ final Map<String, ConnectorObject> externalResources,
+ final ConnectorFactory connFactory) {
+
+ final String schemaName = virAttr.getSchema().getKey();
+ final VirAttrCacheValue virAttrCacheValue = virAttrCache.get(attrUtil.getType(), owner.getKey(), schemaName);
+
+ LOG.debug("Retrieve values for virtual attribute {} ({})", schemaName, type);
+
+ if (virAttrCache.isValidEntry(virAttrCacheValue)) {
+ // cached ...
+ LOG.debug("Values found in cache {}", virAttrCacheValue);
+ virAttr.getValues().clear();
+ virAttr.getValues().addAll(new ArrayList<>(virAttrCacheValue.getValues()));
+ } else {
+ // not cached ...
+ LOG.debug("Need one or more remote connections");
+
+ final VirAttrCacheValue toBeCached = new VirAttrCacheValue();
+
+ // SYNCOPE-458 if virattr owner is a Membership, owner must become user involved in membership because
+ // membership mapping is contained in user mapping
+ final Subject<?, ?, ?> realOwner = owner instanceof Membership
+ ? ((Membership) owner).getUser()
+ : (Subject) owner;
+
+ final Set<ExternalResource> targetResources = owner instanceof Membership
+ ? getTargetResource(virAttr, type, attrUtil, realOwner.getResources())
+ : getTargetResource(virAttr, type, attrUtil);
+
+ for (ExternalResource resource : targetResources) {
+ LOG.debug("Search values into {}", resource.getKey());
+ try {
+ final List<MappingItem> mappings = attrUtil.getMappingItems(resource, MappingPurpose.BOTH);
+
+ final ConnectorObject connectorObject;
+
+ if (externalResources.containsKey(resource.getKey())) {
+ connectorObject = externalResources.get(resource.getKey());
+ } else {
+ LOG.debug("Perform connection to {}", resource.getKey());
+ final String accountId = attrUtil.getAccountIdItem(resource) == null
+ ? null
+ : MappingUtil.getAccountIdValue(
+ realOwner, resource, attrUtil.getAccountIdItem(resource));
+
+ if (StringUtils.isBlank(accountId)) {
+ throw new IllegalArgumentException("No AccountId found for " + resource.getKey());
+ }
+
+ final Connector connector = connFactory.getConnector(resource);
+
+ final OperationOptions oo =
+ connector.getOperationOptions(MappingUtil.getMatchingMappingItems(mappings, type));
+
+ connectorObject = connector.getObject(fromSubject(realOwner), new Uid(accountId), oo);
+ externalResources.put(resource.getKey(), connectorObject);
+ }
+
+ if (connectorObject != null) {
+ // ask for searched virtual attribute value
+ final List<MappingItem> virAttrMappings =
+ MappingUtil.getMatchingMappingItems(mappings, schemaName, type);
+
+ // the same virtual attribute could be mapped with one or more external attribute
+ for (MappingItem mapping : virAttrMappings) {
+ final Attribute attribute = connectorObject.getAttributeByName(mapping.getExtAttrName());
+
+ if (attribute != null && attribute.getValue() != null) {
+ for (Object obj : attribute.getValue()) {
+ if (obj != null) {
+ virAttr.getValues().add(obj.toString());
+ }
+ }
+ }
+ }
+
+ toBeCached.setResourceValues(resource.getKey(), new HashSet<String>(virAttr.getValues()));
+
+ LOG.debug("Retrieved values {}", virAttr.getValues());
+ }
+ } catch (Exception e) {
+ LOG.error("Error reading connector object from {}", resource.getKey(), e);
+
+ if (virAttrCacheValue != null) {
+ toBeCached.forceExpiring();
+ LOG.debug("Search for a cached value (even expired!) ...");
+ final Set<String> cachedValues = virAttrCacheValue.getValues(resource.getKey());
+ if (cachedValues != null) {
+ LOG.debug("Use cached value {}", cachedValues);
+ virAttr.getValues().addAll(cachedValues);
+ toBeCached.setResourceValues(resource.getKey(), new HashSet<>(cachedValues));
+ }
+ }
+ }
+ }
+
+ virAttrCache.put(attrUtil.getType(), owner.getKey(), schemaName, toBeCached);
+ }
+ }
+
+ private Set<ExternalResource> getTargetResource(
+ final VirAttr attr, final IntMappingType type, final AttributableUtil attrUtil) {
+
+ final Set<ExternalResource> resources = new HashSet<>();
+
+ if (attr.getOwner() instanceof Subject) {
+ for (ExternalResource res : ((Subject<?, ?, ?>) attr.getOwner()).getResources()) {
+ if (!MappingUtil.getMatchingMappingItems(
+ attrUtil.getMappingItems(res, MappingPurpose.BOTH),
+ attr.getSchema().getKey(), type).isEmpty()) {
+
+ resources.add(res);
+ }
+ }
+ }
+
+ return resources;
+ }
+
+ private Set<ExternalResource> getTargetResource(final VirAttr attr, final IntMappingType type,
+ final AttributableUtil attrUtil, final Set<? extends ExternalResource> ownerResources) {
+
+ final Set<ExternalResource> resources = new HashSet<>();
+
+ for (ExternalResource res : ownerResources) {
+ if (!MappingUtil.getMatchingMappingItems(
+ attrUtil.getMappingItems(res, MappingPurpose.BOTH),
+ attr.getSchema().getKey(), type).isEmpty()) {
+
+ resources.add(res);
+ }
+ }
+
+ return resources;
+ }
+
+ private void fillFromTemplate(final AbstractAttributableTO attributableTO, final AbstractAttributableTO template) {
+ Map<String, AttrTO> currentAttrMap = attributableTO.getAttrMap();
+ for (AttrTO templateAttr : template.getPlainAttrs()) {
+ if (templateAttr.getValues() != null && !templateAttr.getValues().isEmpty()
+ && (!currentAttrMap.containsKey(templateAttr.getSchema())
+ || currentAttrMap.get(templateAttr.getSchema()).getValues().isEmpty())) {
+
+ attributableTO.getPlainAttrs().add(evaluateAttrTemplate(attributableTO, templateAttr));
+ }
+ }
+
+ currentAttrMap = attributableTO.getDerAttrMap();
+ for (AttrTO templateDerAttr : template.getDerAttrs()) {
+ if (!currentAttrMap.containsKey(templateDerAttr.getSchema())) {
+ attributableTO.getDerAttrs().add(templateDerAttr);
+ }
+ }
+
+ currentAttrMap = attributableTO.getVirAttrMap();
+ for (AttrTO templateVirAttr : template.getVirAttrs()) {
+ if (templateVirAttr.getValues() != null && !templateVirAttr.getValues().isEmpty()
+ && (!currentAttrMap.containsKey(templateVirAttr.getSchema())
+ || currentAttrMap.get(templateVirAttr.getSchema()).getValues().isEmpty())) {
+
+ attributableTO.getVirAttrs().add(evaluateAttrTemplate(attributableTO, templateVirAttr));
+ }
+ }
+ }
+
+ private AttrTO evaluateAttrTemplate(final AbstractAttributableTO attributableTO, final AttrTO template) {
+ AttrTO result = new AttrTO();
+ result.setSchema(template.getSchema());
+
+ if (template.getValues() != null && !template.getValues().isEmpty()) {
+ for (String value : template.getValues()) {
+ String evaluated = JexlUtil.evaluate(value, attributableTO);
+ if (StringUtils.isNotBlank(evaluated)) {
+ result.getValues().add(evaluated);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Transform a
+ * <code>Collection</code> of {@link Attribute} instances into a {@link Map}. The key to each element in the map is
+ * the <i>name</i> of an
+ * <code>Attribute</code>. The value of each element in the map is the
+ * <code>Attribute</code> instance with that name. <br/> Different from the original because: <ul> <li>map keys are
+ * transformed toUpperCase()</li> <li>returned map is mutable</li> </ul>
+ *
+ * @param attributes set of attribute to transform to a map.
+ * @return a map of string and attribute.
+ *
+ * @see org.identityconnectors.framework.common.objects.AttributeUtil#toMap(java.util.Collection)
+ */
+ public Map<String, Attribute> toMap(final Collection<? extends Attribute> attributes) {
+ final Map<String, Attribute> map = new HashMap<>();
+ for (Attribute attr : attributes) {
+ map.put(attr.getName().toUpperCase(), attr);
+ }
+ return map;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/ExceptionUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/ExceptionUtil.java b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/ExceptionUtil.java
new file mode 100644
index 0000000..5a39faf
--- /dev/null
+++ b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/ExceptionUtil.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.server.utils;
+
+import org.apache.commons.lang3.exception.ExceptionUtils;
+
+public final class ExceptionUtil {
+
+ /**
+ * 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 ExceptionUtil() {
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/InvalidPasswordPolicySpecException.java
----------------------------------------------------------------------
diff --git a/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/InvalidPasswordPolicySpecException.java b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/InvalidPasswordPolicySpecException.java
new file mode 100644
index 0000000..8c97a1c
--- /dev/null
+++ b/syncope620/server/utils/src/main/java/org/apache/syncope/server/utils/InvalidPasswordPolicySpecException.java
@@ -0,0 +1,37 @@
+/*
+ * 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.server.utils;
+
+/**
+ * Raise when the merge of two or more PasswordPolicySpec leds to incompatible condition.
+ *
+ * @see org.apache.syncope.common.lib.types.PasswordPolicySpec
+ */
+public class InvalidPasswordPolicySpecException extends Exception {
+
+ private static final long serialVersionUID = 4810651743226663580L;
+
+ public InvalidPasswordPolicySpecException(final String msg) {
+ super(msg);
+ }
+
+ public InvalidPasswordPolicySpecException(final String msg, final Exception e) {
+ super(msg, e);
+ }
+}
[10/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/PropagationActionClass.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/PropagationActionClass.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/PropagationActionClass.java
new file mode 100644
index 0000000..f8e54b6
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/PropagationActionClass.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "propagationActionClass")
+@XmlType
+public class PropagationActionClass extends AbstractWrappable<String> {
+
+ private static final long serialVersionUID = 2187654394121198308L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/PushActionClass.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/PushActionClass.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/PushActionClass.java
new file mode 100644
index 0000000..e12fd8e
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/PushActionClass.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "pushActionClass")
+@XmlType
+public class PushActionClass extends AbstractWrappable<String> {
+
+ private static final long serialVersionUID = 1669581609310071906L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ReportletConfClass.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ReportletConfClass.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ReportletConfClass.java
new file mode 100644
index 0000000..24ba188
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ReportletConfClass.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "reportletConfClass")
+@XmlType
+public class ReportletConfClass extends AbstractWrappable<String> {
+
+ private static final long serialVersionUID = 1343357929074360450L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ResourceName.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ResourceName.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ResourceName.java
new file mode 100644
index 0000000..42b77ca
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ResourceName.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "resourceName")
+@XmlType
+public class ResourceName extends AbstractWrappable<String> {
+
+ private static final long serialVersionUID = -175720097924079573L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/SubjectId.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/SubjectId.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/SubjectId.java
new file mode 100644
index 0000000..d61f1d9
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/SubjectId.java
@@ -0,0 +1,25 @@
+/*
+ * 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.common.lib.wrap;
+
+public class SubjectId extends AbstractWrappable<Long> {
+
+ private static final long serialVersionUID = -8664228651057889297L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/SyncActionClass.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/SyncActionClass.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/SyncActionClass.java
new file mode 100644
index 0000000..d6c7a77
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/SyncActionClass.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "syncActionClass")
+@XmlType
+public class SyncActionClass extends AbstractWrappable<String> {
+
+ private static final long serialVersionUID = 1669581609310071905L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/Validator.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/Validator.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/Validator.java
new file mode 100644
index 0000000..71cad00
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/Validator.java
@@ -0,0 +1,30 @@
+/*
+ * 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.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "validator")
+@XmlType
+public class Validator extends AbstractWrappable<String> {
+
+ private static final long serialVersionUID = 7233619557177034453L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/package-info.java
----------------------------------------------------------------------
diff --git a/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/package-info.java b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/package-info.java
new file mode 100644
index 0000000..397cb66
--- /dev/null
+++ b/syncope620/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+@XmlSchema(namespace = SyncopeConstants.NAMESPACE)
+package org.apache.syncope.common.lib.wrap;
+
+import javax.xml.bind.annotation.XmlSchema;
+import org.apache.syncope.common.lib.SyncopeConstants;
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/pom.xml b/syncope620/pom.xml
index 82e910d..ad69b63 100644
--- a/syncope620/pom.xml
+++ b/syncope620/pom.xml
@@ -320,6 +320,8 @@ under the License.
<connid.ldap.version>1.4.0</connid.ldap.version>
<connid.ad.version>1.2.1</connid.ad.version>
+ <cxf.version>3.0.3</cxf.version>
+
<jackson.version>2.5.0</jackson.version>
<spring.version>4.1.4.RELEASE</spring.version>
@@ -333,7 +335,9 @@ under the License.
<quartz.version>2.2.1</quartz.version>
- <slf4j.version>1.7.9</slf4j.version>
+ <cocoon.version>3.0.0-alpha-3</cocoon.version>
+
+ <slf4j.version>1.7.10</slf4j.version>
<log4j.version>2.1</log4j.version>
<commons-io.version>2.4</commons-io.version>
@@ -379,6 +383,49 @@ under the License.
<version>3.0.0</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>javax.ws.rs-api</artifactId>
+ <version>2.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.javamail</groupId>
+ <artifactId>geronimo-javamail_1.4_mail</artifactId>
+ <version>1.8.4</version>
+ </dependency>
+
+ <!-- CXF -->
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxrs</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-extension-providers</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-extension-search</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-frontend-jaxws</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-service-description</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-client</artifactId>
+ <version>${cxf.version}</version>
+ </dependency>
+ <!-- /CXF -->
<dependency>
<groupId>org.apache.openjpa</groupId>
@@ -436,6 +483,11 @@ under the License.
</dependency>
<dependency>
<groupId>org.springframework</groupId>
+ <artifactId>spring-context-support</artifactId>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
@@ -454,6 +506,12 @@ under the License.
<artifactId>spring-security-core</artifactId>
<version>${spring-security.version}</version>
</dependency>
+
+ <dependency>
+ <groupId>org.aspectj</groupId>
+ <artifactId>aspectjweaver</artifactId>
+ <version>1.8.4</version>
+ </dependency>
<dependency>
<groupId>commons-io</groupId>
@@ -517,6 +575,87 @@ under the License.
</dependency>
<dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity</artifactId>
+ <version>1.7</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity-tools</artifactId>
+ <version>2.0</version>
+ <exclusions>
+ <exclusion>
+ <artifactId>struts-core</artifactId>
+ <groupId>org.apache.struts</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>struts-taglib</artifactId>
+ <groupId>org.apache.struts</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>struts-tiles</artifactId>
+ <groupId>org.apache.struts</groupId>
+ </exclusion>
+ <exclusion>
+ <artifactId>sslext</artifactId>
+ <groupId>sslext</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.cocoon.sax</groupId>
+ <artifactId>cocoon-sax</artifactId>
+ <version>${cocoon.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cocoon.optional</groupId>
+ <artifactId>cocoon-optional</artifactId>
+ <version>${cocoon.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.xmlgraphics</groupId>
+ <artifactId>fop</artifactId>
+ <version>1.1</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.avalon.framework</groupId>
+ <artifactId>avalon-framework-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.apache.avalon.framework</groupId>
+ <artifactId>avalon-framework-impl</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.avalon.framework</groupId>
+ <artifactId>avalon-framework-api</artifactId>
+ <version>4.3.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.avalon.framework</groupId>
+ <artifactId>avalon-framework-impl</artifactId>
+ <version>4.3.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ <version>2.7.1</version>
+ </dependency>
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ <version>2.11.0</version>
+ </dependency>
+
+ <dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
@@ -526,6 +665,11 @@ under the License.
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ <version>${log4j.version}</version>
+ </dependency>
<dependency>
<groupId>org.springframework</groupId>
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/pom.xml b/syncope620/server/logic/pom.xml
new file mode 100644
index 0000000..fd8fc42
--- /dev/null
+++ b/syncope620/server/logic/pom.xml
@@ -0,0 +1,127 @@
+<?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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.syncope</groupId>
+ <artifactId>syncope-server</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </parent>
+
+ <name>Apache Syncope Server Logic</name>
+ <description>Apache Syncope Server Logic</description>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-server-logic</artifactId>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.geronimo.javamail</groupId>
+ <artifactId>geronimo-javamail_1.4_mail</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-dbcp2</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context-support</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-jdbc</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.aspectj</groupId>
+ <artifactId>aspectjweaver</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity-tools</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.cocoon.sax</groupId>
+ <artifactId>cocoon-sax</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cocoon.optional</groupId>
+ <artifactId>cocoon-optional</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.xmlgraphics</groupId>
+ <artifactId>fop</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.avalon.framework</groupId>
+ <artifactId>avalon-framework-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.avalon.framework</groupId>
+ <artifactId>avalon-framework-impl</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-core</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-persistence-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-workflow-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.syncope.server</groupId>
+ <artifactId>syncope-server-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractLogic.java
new file mode 100644
index 0000000..11686a2
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractLogic.java
@@ -0,0 +1,58 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Superclass for all controllers.
+ *
+ * @param <T> transfer object used for input / output
+ */
+abstract class AbstractLogic<T extends AbstractBaseBean> {
+
+ /**
+ * Logger.
+ */
+ protected static final Logger LOG = LoggerFactory.getLogger(AbstractLogic.class);
+
+ /**
+ * Resolves stored bean (if existing) referred by the given CUD method.
+ * <br />
+ * Read-only methods will be unresolved for performance reasons.
+ *
+ * @param method method.
+ * @param args method arguments.
+ * @return referred stored bean.
+ * @throws UnresolvedReferenceException in case of failures, read-only methods and unresolved bean.
+ */
+ public T resolveBeanReference(final Method method, final Object... args) throws UnresolvedReferenceException {
+ final Transactional transactional = method.getAnnotation(Transactional.class);
+ if (transactional != null && transactional.readOnly()) {
+ throw new UnresolvedReferenceException();
+ }
+ return resolveReference(method, args);
+ }
+
+ protected abstract T resolveReference(Method method, Object... args) throws UnresolvedReferenceException;
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractResourceAssociator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractResourceAssociator.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractResourceAssociator.java
new file mode 100644
index 0000000..2a20d1f
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractResourceAssociator.java
@@ -0,0 +1,37 @@
+/*
+ * 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.server.logic;
+
+import java.util.Collection;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+
+public abstract class AbstractResourceAssociator<T extends AbstractAttributableTO> extends AbstractLogic<T> {
+
+ public abstract T unlink(Long id, Collection<String> resources);
+
+ public abstract T link(Long id, Collection<String> resources);
+
+ public abstract T unassign(Long id, Collection<String> resources);
+
+ public abstract T assign(Long id, Collection<String> resources, boolean changepwd, String password);
+
+ public abstract T deprovision(Long userId, Collection<String> resources);
+
+ public abstract T provision(Long userId, Collection<String> resources, boolean changepwd, String password);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractSubjectLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractSubjectLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractSubjectLogic.java
new file mode 100644
index 0000000..a9117b8
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractSubjectLogic.java
@@ -0,0 +1,43 @@
+/*
+ * 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.server.logic;
+
+import java.util.List;
+import org.apache.syncope.common.lib.mod.AbstractSubjectMod;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.persistence.api.dao.search.SearchCond;
+
+public abstract class AbstractSubjectLogic<T extends AbstractSubjectTO, V extends AbstractSubjectMod>
+ extends AbstractResourceAssociator<T> {
+
+ public abstract T read(Long key);
+
+ public abstract int count();
+
+ public abstract T update(V attributableMod);
+
+ public abstract T delete(Long key);
+
+ public abstract List<T> list(int page, int size, List<OrderByClause> orderBy);
+
+ public abstract List<T> search(SearchCond searchCondition, int page, int size, List<OrderByClause> orderBy);
+
+ public abstract int searchCount(SearchCond searchCondition);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractTransactionalLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractTransactionalLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractTransactionalLogic.java
new file mode 100644
index 0000000..00526b8
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/AbstractTransactionalLogic.java
@@ -0,0 +1,31 @@
+/*
+ * 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.server.logic;
+
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Adds Spring's transactional support to {@link AbstractLogic}.
+ *
+ * @param <T> transfer object used for input / output
+ */
+@Transactional(rollbackFor = { Throwable.class })
+abstract class AbstractTransactionalLogic<T extends AbstractBaseBean> extends AbstractLogic<T> {
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ConfigurationLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ConfigurationLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ConfigurationLogic.java
new file mode 100644
index 0000000..581f640
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ConfigurationLogic.java
@@ -0,0 +1,157 @@
+/*
+ * 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.server.logic;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ConfTO;
+import org.apache.syncope.common.lib.wrap.Validator;
+import org.apache.syncope.persistence.api.content.ContentExporter;
+import org.apache.syncope.persistence.api.dao.ConfDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.persistence.api.entity.conf.CPlainSchema;
+import org.apache.syncope.server.logic.data.ConfigurationDataBinder;
+import org.apache.syncope.server.logic.init.ImplementationClassNamesLoader;
+import org.apache.syncope.server.logic.init.WorkflowAdapterLoader;
+import org.apache.syncope.server.logic.notification.NotificationManager;
+import org.apache.syncope.server.spring.ResourceWithFallbackLoader;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class ConfigurationLogic extends AbstractTransactionalLogic<ConfTO> {
+
+ @Autowired
+ private ConfDAO confDAO;
+
+ @Autowired
+ private PlainSchemaDAO plainSchemaDAO;
+
+ @Autowired
+ private ConfigurationDataBinder binder;
+
+ @Autowired
+ private ContentExporter exporter;
+
+ @Autowired
+ private ImplementationClassNamesLoader classNamesLoader;
+
+ @javax.annotation.Resource(name = "velocityResourceLoader")
+ private ResourceWithFallbackLoader resourceLoader;
+
+ @Autowired
+ private WorkflowAdapterLoader wfAdapterLoader;
+
+ @PreAuthorize("hasRole('CONFIGURATION_DELETE')")
+ public void delete(final String key) {
+ confDAO.delete(key);
+ }
+
+ @PreAuthorize("hasRole('CONFIGURATION_LIST')")
+ public ConfTO list() {
+ return binder.getConfTO(confDAO.get());
+ }
+
+ @PreAuthorize("isAuthenticated()")
+ public AttrTO read(final String key) {
+ AttrTO result;
+
+ CPlainAttr conf = confDAO.find(key);
+ if (conf == null) {
+ CPlainSchema schema = plainSchemaDAO.find(key, CPlainSchema.class);
+ if (schema == null) {
+ throw new NotFoundException("Configuration key " + key);
+ }
+
+ result = new AttrTO();
+ result.setSchema(key);
+ } else {
+ result = binder.getAttrTO(conf);
+ }
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('CONFIGURATION_SET')")
+ public void set(final AttrTO value) {
+ confDAO.save(binder.getAttribute(value));
+ }
+
+ @PreAuthorize("hasRole('CONFIGURATION_LIST')")
+ public Set<String> getValidators() {
+ return classNamesLoader.getClassNames(ImplementationClassNamesLoader.Type.VALIDATOR);
+ }
+
+ @PreAuthorize("hasRole('CONFIGURATION_LIST')")
+ public Set<String> getMailTemplates() {
+ Set<String> htmlTemplates = new HashSet<String>();
+ Set<String> textTemplates = new HashSet<String>();
+
+ try {
+ for (Resource resource : resourceLoader.getResources(NotificationManager.MAIL_TEMPLATES + "*.vm")) {
+ String template = resource.getURL().toExternalForm();
+ if (template.endsWith(NotificationManager.MAIL_TEMPLATE_HTML_SUFFIX)) {
+ htmlTemplates.add(
+ template.substring(template.indexOf(NotificationManager.MAIL_TEMPLATES) + 14,
+ template.indexOf(NotificationManager.MAIL_TEMPLATE_HTML_SUFFIX)));
+ } else if (template.endsWith(NotificationManager.MAIL_TEMPLATE_TEXT_SUFFIX)) {
+ textTemplates.add(
+ template.substring(template.indexOf(NotificationManager.MAIL_TEMPLATES) + 14,
+ template.indexOf(NotificationManager.MAIL_TEMPLATE_TEXT_SUFFIX)));
+ } else {
+ LOG.warn("Unexpected template found: {}, ignoring...", template);
+ }
+ }
+ } catch (IOException e) {
+ LOG.error("While searching for class implementing {}", Validator.class.getName(), e);
+ }
+
+ // Only templates available both as HTML and TEXT are considered
+ htmlTemplates.retainAll(textTemplates);
+
+ return htmlTemplates;
+ }
+
+ @PreAuthorize("hasRole('CONFIGURATION_EXPORT')")
+ @Transactional(readOnly = true)
+ public void export(final OutputStream os) {
+ try {
+ exporter.export(os, wfAdapterLoader.getTablePrefix());
+ LOG.debug("Database content successfully exported");
+ } catch (Exception e) {
+ LOG.error("While exporting database content", e);
+ }
+ }
+
+ @Override
+ protected ConfTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ConnectorLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ConnectorLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ConnectorLogic.java
new file mode 100644
index 0000000..ee550cd
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/ConnectorLogic.java
@@ -0,0 +1,341 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.ConnBundleTO;
+import org.apache.syncope.common.lib.to.ConnInstanceTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ConnConfProperty;
+import org.apache.syncope.persistence.api.dao.ConnInstanceDAO;
+import org.apache.syncope.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.entity.ConnInstance;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.provisioning.api.ConnIdBundleManager;
+import org.apache.syncope.provisioning.api.Connector;
+import org.apache.syncope.provisioning.api.ConnectorFactory;
+import org.apache.syncope.server.logic.data.ConnInstanceDataBinder;
+import org.identityconnectors.common.l10n.CurrentLocale;
+import org.identityconnectors.framework.api.ConfigurationProperties;
+import org.identityconnectors.framework.api.ConnectorInfo;
+import org.identityconnectors.framework.api.ConnectorKey;
+import org.identityconnectors.framework.common.objects.ObjectClass;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class ConnectorLogic extends AbstractTransactionalLogic<ConnInstanceTO> {
+
+ @Autowired
+ private ConnIdBundleManager connIdBundleManager;
+
+ @Autowired
+ private ExternalResourceDAO resourceDAO;
+
+ @Autowired
+ private ConnInstanceDAO connInstanceDAO;
+
+ @Autowired
+ private ConnInstanceDataBinder binder;
+
+ @Autowired
+ private ConnectorFactory connFactory;
+
+ @PreAuthorize("hasRole('CONNECTOR_CREATE')")
+ public ConnInstanceTO create(final ConnInstanceTO connInstanceTO) {
+ ConnInstance connInstance = binder.getConnInstance(connInstanceTO);
+ try {
+ connInstance = connInstanceDAO.save(connInstance);
+ } catch (SyncopeClientException e) {
+ throw e;
+ } catch (Exception e) {
+ SyncopeClientException ex = SyncopeClientException.build(ClientExceptionType.InvalidConnInstance);
+ ex.getElements().add(e.getMessage());
+ throw ex;
+ }
+
+ return binder.getConnInstanceTO(connInstance);
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_UPDATE')")
+ public ConnInstanceTO update(final ConnInstanceTO connInstanceTO) {
+ ConnInstance connInstance = binder.updateConnInstance(connInstanceTO.getKey(), connInstanceTO);
+ try {
+ connInstance = connInstanceDAO.save(connInstance);
+ } catch (SyncopeClientException e) {
+ throw e;
+ } catch (Exception e) {
+ SyncopeClientException ex = SyncopeClientException.build(ClientExceptionType.InvalidConnInstance);
+ ex.getElements().add(e.getMessage());
+ throw ex;
+ }
+
+ return binder.getConnInstanceTO(connInstance);
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_DELETE')")
+ public ConnInstanceTO delete(final Long connInstanceId) {
+ ConnInstance connInstance = connInstanceDAO.find(connInstanceId);
+ if (connInstance == null) {
+ throw new NotFoundException("Connector '" + connInstanceId + "'");
+ }
+
+ if (!connInstance.getResources().isEmpty()) {
+ SyncopeClientException associatedResources = SyncopeClientException.build(
+ ClientExceptionType.AssociatedResources);
+ for (ExternalResource resource : connInstance.getResources()) {
+ associatedResources.getElements().add(resource.getKey());
+ }
+ throw associatedResources;
+ }
+
+ ConnInstanceTO connToDelete = binder.getConnInstanceTO(connInstance);
+
+ connInstanceDAO.delete(connInstanceId);
+
+ return connToDelete;
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_LIST')")
+ @Transactional(readOnly = true)
+ public List<ConnInstanceTO> list(final String lang) {
+ if (StringUtils.isBlank(lang)) {
+ CurrentLocale.set(Locale.ENGLISH);
+ } else {
+ CurrentLocale.set(new Locale(lang));
+ }
+
+ List<ConnInstance> connInstances = connInstanceDAO.findAll();
+
+ final List<ConnInstanceTO> connInstanceTOs = new ArrayList<>();
+
+ for (ConnInstance connector : connInstances) {
+ try {
+ connInstanceTOs.add(binder.getConnInstanceTO(connector));
+ } catch (NotFoundException e) {
+ LOG.error("Connector '{}#{}' not found", connector.getBundleName(), connector.getVersion());
+ }
+ }
+
+ return connInstanceTOs;
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_READ')")
+ @Transactional(readOnly = true)
+ public ConnInstanceTO read(final Long connInstanceId) {
+ ConnInstance connInstance = connInstanceDAO.find(connInstanceId);
+ if (connInstance == null) {
+ throw new NotFoundException("Connector '" + connInstanceId + "'");
+ }
+
+ return binder.getConnInstanceTO(connInstance);
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_READ')")
+ @Transactional(readOnly = true)
+ public List<ConnBundleTO> getBundles(final String lang) {
+ if (StringUtils.isBlank(lang)) {
+ CurrentLocale.set(Locale.ENGLISH);
+ } else {
+ CurrentLocale.set(new Locale(lang));
+ }
+
+ List<ConnBundleTO> connectorBundleTOs = new ArrayList<>();
+ for (Map.Entry<String, List<ConnectorInfo>> entry : connIdBundleManager.getConnectorInfos().entrySet()) {
+ for (ConnectorInfo bundle : entry.getValue()) {
+ ConnBundleTO connBundleTO = new ConnBundleTO();
+ connBundleTO.setDisplayName(bundle.getConnectorDisplayName());
+
+ connBundleTO.setLocation(entry.getKey());
+
+ ConnectorKey key = bundle.getConnectorKey();
+ connBundleTO.setBundleName(key.getBundleName());
+ connBundleTO.setConnectorName(key.getConnectorName());
+ connBundleTO.setVersion(key.getBundleVersion());
+
+ ConfigurationProperties properties = connIdBundleManager.getConfigurationProperties(bundle);
+
+ for (String propName : properties.getPropertyNames()) {
+ connBundleTO.getProperties().add(binder.buildConnConfPropSchema(properties.getProperty(propName)));
+ }
+
+ LOG.debug("Connector bundle: {}", connBundleTO);
+
+ connectorBundleTOs.add(connBundleTO);
+ }
+ }
+
+ return connectorBundleTOs;
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_READ')")
+ @Transactional(readOnly = true)
+ public List<String> getSchemaNames(final ConnInstanceTO connInstanceTO, final boolean includeSpecial) {
+ final ConnInstance connInstance = connInstanceDAO.find(connInstanceTO.getKey());
+ if (connInstance == null) {
+ throw new NotFoundException("Connector '" + connInstanceTO.getKey() + "'");
+ }
+
+ // consider the possibility to receive overridden properties only
+ final Set<ConnConfProperty> conf = binder.mergeConnConfProperties(connInstanceTO.getConfiguration(),
+ connInstance.getConfiguration());
+
+ // We cannot use Spring bean because this method could be used during resource definition or modification:
+ // bean couldn't exist or couldn't be updated.
+ // This is the reason why we should take a "not mature" connector facade proxy to ask for schema names.
+ final List<String> result = new ArrayList<>(connFactory.createConnector(connInstance, conf).
+ getSchemaNames(includeSpecial));
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_READ')")
+ @Transactional(readOnly = true)
+ public List<String> getSupportedObjectClasses(final ConnInstanceTO connInstanceTO) {
+ final ConnInstance connInstance = connInstanceDAO.find(connInstanceTO.getKey());
+ if (connInstance == null) {
+ throw new NotFoundException("Connector '" + connInstanceTO.getKey() + "'");
+ }
+
+ // consider the possibility to receive overridden properties only
+ final Set<ConnConfProperty> conf = binder.mergeConnConfProperties(connInstanceTO.getConfiguration(),
+ connInstance.getConfiguration());
+
+ // We cannot use Spring bean because this method could be used during resource definition or modification:
+ // bean couldn't exist or couldn't be updated.
+ // This is the reason why we should take a "not mature" connector facade proxy to ask for object classes.
+ Set<ObjectClass> objectClasses = connFactory.createConnector(connInstance, conf).getSupportedObjectClasses();
+
+ List<String> result = new ArrayList<>(objectClasses.size());
+ for (ObjectClass objectClass : objectClasses) {
+ result.add(objectClass.getObjectClassValue());
+ }
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_READ')")
+ @Transactional(readOnly = true)
+ public List<ConnConfProperty> getConfigurationProperties(final Long connInstanceId) {
+
+ final ConnInstance connInstance = connInstanceDAO.find(connInstanceId);
+ if (connInstance == null) {
+ throw new NotFoundException("Connector '" + connInstanceId + "'");
+ }
+
+ return new ArrayList<ConnConfProperty>(connInstance.getConfiguration());
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_READ')")
+ @Transactional(readOnly = true)
+ public boolean check(final ConnInstanceTO connInstanceTO) {
+ final Connector connector = connFactory.createConnector(
+ binder.getConnInstance(connInstanceTO), connInstanceTO.getConfiguration());
+
+ boolean result;
+ try {
+ connector.test();
+ result = true;
+ } catch (Exception ex) {
+ LOG.error("Test connection failure {}", ex);
+ result = false;
+ }
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_READ')")
+ @Transactional(readOnly = true)
+ public ConnInstanceTO readByResource(final String resourceName) {
+ ExternalResource resource = resourceDAO.find(resourceName);
+ if (resource == null) {
+ throw new NotFoundException("Resource '" + resourceName + "'");
+ }
+ return binder.getConnInstanceTO(connFactory.getConnector(resource).getActiveConnInstance());
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_RELOAD')")
+ @Transactional(readOnly = true)
+ public void reload() {
+ connFactory.unload();
+ connFactory.load();
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_DELETE') and #bulkAction.operation == #bulkAction.operation.DELETE")
+ public BulkActionResult bulk(final BulkAction bulkAction) {
+ BulkActionResult res = new BulkActionResult();
+
+ if (bulkAction.getOperation() == BulkAction.Type.DELETE) {
+ for (String id : bulkAction.getTargets()) {
+ try {
+ res.add(delete(Long.valueOf(id)).getKey(), BulkActionResult.Status.SUCCESS);
+ } catch (Exception e) {
+ LOG.error("Error performing delete for connector {}", id, e);
+ res.add(id, BulkActionResult.Status.FAILURE);
+ }
+ }
+ }
+
+ return res;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ConnInstanceTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ Long id = null;
+
+ if (ArrayUtils.isNotEmpty(args)) {
+ for (int i = 0; id == null && i < args.length; i++) {
+ if (args[i] instanceof Long) {
+ id = (Long) args[i];
+ } else if (args[i] instanceof ConnInstanceTO) {
+ id = ((ConnInstanceTO) args[i]).getKey();
+ }
+ }
+ }
+
+ if ((id != null) && !id.equals(0l)) {
+ try {
+ return binder.getConnInstanceTO(connInstanceDAO.find(id));
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/EntitlementLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/EntitlementLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/EntitlementLogic.java
new file mode 100644
index 0000000..e71fcb9
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/EntitlementLogic.java
@@ -0,0 +1,58 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import org.apache.syncope.common.lib.wrap.EntitlementTO;
+import org.apache.syncope.persistence.api.dao.EntitlementDAO;
+import org.apache.syncope.persistence.api.entity.Entitlement;
+import org.apache.syncope.server.security.AuthContextUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class EntitlementLogic extends AbstractTransactionalLogic<EntitlementTO> {
+
+ @Autowired
+ private EntitlementDAO entitlementDAO;
+
+ public List<String> getAll() {
+ List<Entitlement> entitlements = entitlementDAO.findAll();
+ List<String> result = new ArrayList<String>(entitlements.size());
+ for (Entitlement entitlement : entitlements) {
+ result.add(entitlement.getKey());
+ }
+
+ return result;
+ }
+
+ public Set<String> getOwn() {
+ return AuthContextUtil.getOwnedEntitlementNames();
+ }
+
+ @Override
+ protected EntitlementTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/LoggerLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/LoggerLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/LoggerLogic.java
new file mode 100644
index 0000000..5356b86
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/LoggerLogic.java
@@ -0,0 +1,307 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.EventCategoryTO;
+import org.apache.syncope.common.lib.to.LoggerTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.AuditElements.EventCategoryType;
+import org.apache.syncope.common.lib.types.AuditLoggerName;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.LoggerLevel;
+import org.apache.syncope.common.lib.types.LoggerType;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.persistence.api.dao.LoggerDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.TaskDAO;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.Logger;
+import org.apache.syncope.persistence.api.entity.task.SchedTask;
+import org.apache.syncope.persistence.api.entity.task.SyncTask;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.SystemPropertyUtils;
+
+@Component
+public class LoggerLogic extends AbstractTransactionalLogic<LoggerTO> {
+
+ @Autowired
+ private LoggerDAO loggerDAO;
+
+ @Autowired
+ private ExternalResourceDAO resourceDAO;
+
+ @Autowired
+ private TaskDAO taskDAO;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ private List<LoggerTO> list(final LoggerType type) {
+ List<LoggerTO> result = new ArrayList<>();
+ for (Logger syncopeLogger : loggerDAO.findAll(type)) {
+ LoggerTO loggerTO = new LoggerTO();
+ BeanUtils.copyProperties(syncopeLogger, loggerTO);
+ result.add(loggerTO);
+ }
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('LOG_LIST')")
+ @Transactional(readOnly = true)
+ public List<LoggerTO> listLogs() {
+ return list(LoggerType.LOG);
+ }
+
+ @PreAuthorize("hasRole('AUDIT_LIST')")
+ @Transactional(readOnly = true)
+ public List<AuditLoggerName> listAudits() {
+ List<AuditLoggerName> result = new ArrayList<>();
+
+ for (LoggerTO logger : list(LoggerType.AUDIT)) {
+ try {
+ result.add(AuditLoggerName.fromLoggerName(logger.getName()));
+ } catch (Exception e) {
+ LOG.warn("Unexpected audit logger name: {}", logger.getName(), e);
+ }
+ }
+
+ return result;
+ }
+
+ private void throwInvalidLogger(final LoggerType type) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidLogger);
+ sce.getElements().add("Expected " + type.name());
+
+ throw sce;
+ }
+
+ private LoggerTO setLevel(final String name, final Level level, final LoggerType expectedType) {
+ Logger syncopeLogger = loggerDAO.find(name);
+ if (syncopeLogger == null) {
+ LOG.debug("Logger {} not found: creating new...", name);
+
+ syncopeLogger = entityFactory.newEntity(Logger.class);
+ syncopeLogger.setKey(name);
+ syncopeLogger.setType(name.startsWith(LoggerType.AUDIT.getPrefix())
+ ? LoggerType.AUDIT
+ : LoggerType.LOG);
+ }
+
+ if (expectedType != syncopeLogger.getType()) {
+ throwInvalidLogger(expectedType);
+ }
+
+ syncopeLogger.setLevel(LoggerLevel.fromLevel(level));
+ syncopeLogger = loggerDAO.save(syncopeLogger);
+
+ LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+ LoggerConfig logConf = SyncopeConstants.ROOT_LOGGER.equals(name)
+ ? ctx.getConfiguration().getLoggerConfig(LogManager.ROOT_LOGGER_NAME)
+ : ctx.getConfiguration().getLoggerConfig(name);
+ logConf.setLevel(level);
+ ctx.updateLoggers();
+
+ LoggerTO result = new LoggerTO();
+ BeanUtils.copyProperties(syncopeLogger, result);
+
+ return result;
+ }
+
+ @PreAuthorize("hasRole('LOG_SET_LEVEL')")
+ public LoggerTO setLogLevel(final String name, final Level level) {
+ return setLevel(name, level, LoggerType.LOG);
+ }
+
+ @PreAuthorize("hasRole('AUDIT_ENABLE')")
+ public void enableAudit(final AuditLoggerName auditLoggerName) {
+ try {
+ setLevel(auditLoggerName.toLoggerName(), Level.DEBUG, LoggerType.AUDIT);
+ } catch (IllegalArgumentException e) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidLogger);
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
+ }
+
+ private LoggerTO delete(final String name, final LoggerType expectedType) throws NotFoundException {
+ Logger syncopeLogger = loggerDAO.find(name);
+ if (syncopeLogger == null) {
+ throw new NotFoundException("Logger " + name);
+ } else if (expectedType != syncopeLogger.getType()) {
+ throwInvalidLogger(expectedType);
+ }
+
+ LoggerTO loggerToDelete = new LoggerTO();
+ BeanUtils.copyProperties(syncopeLogger, loggerToDelete);
+
+ // remove SyncopeLogger from local storage, so that LoggerLoader won't load this next time
+ loggerDAO.delete(syncopeLogger);
+
+ // set log level to OFF in order to disable configured logger until next reboot
+ LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+ org.apache.logging.log4j.core.Logger logger = SyncopeConstants.ROOT_LOGGER.equals(name)
+ ? ctx.getLogger(LogManager.ROOT_LOGGER_NAME) : ctx.getLogger(name);
+ logger.setLevel(Level.OFF);
+ ctx.updateLoggers();
+
+ return loggerToDelete;
+ }
+
+ @PreAuthorize("hasRole('LOG_DELETE')")
+ public LoggerTO deleteLog(final String name) throws NotFoundException {
+ return delete(name, LoggerType.LOG);
+ }
+
+ @PreAuthorize("hasRole('AUDIT_DISABLE')")
+ public void disableAudit(final AuditLoggerName auditLoggerName) {
+ try {
+ delete(auditLoggerName.toLoggerName(), LoggerType.AUDIT);
+ } catch (NotFoundException e) {
+ LOG.debug("Ignoring disable of non existing logger {}", auditLoggerName.toLoggerName());
+ } catch (IllegalArgumentException e) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidLogger);
+ sce.getElements().add(e.getMessage());
+ throw sce;
+ }
+ }
+
+ @PreAuthorize("hasRole('AUDIT_LIST') or hasRole('NOTIFICATION_LIST')")
+ public List<EventCategoryTO> listAuditEvents() {
+ // use set to avoi duplications or null elements
+ final Set<EventCategoryTO> events = new HashSet<EventCategoryTO>();
+
+ try {
+ final ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
+ final MetadataReaderFactory metadataReaderFactory =
+ new CachingMetadataReaderFactory(resourcePatternResolver);
+
+ final String packageSearchPath =
+ ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ + ClassUtils.convertClassNameToResourcePath(
+ SystemPropertyUtils.resolvePlaceholders(this.getClass().getPackage().getName()))
+ + "/" + "**/*.class";
+
+ final Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
+ for (Resource resource : resources) {
+ if (resource.isReadable()) {
+ final MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
+ final Class<?> clazz = Class.forName(metadataReader.getClassMetadata().getClassName());
+
+ if (clazz.isAnnotationPresent(Component.class)
+ && AbstractLogic.class.isAssignableFrom(clazz)) {
+ final EventCategoryTO eventCategoryTO = new EventCategoryTO();
+ eventCategoryTO.setCategory(clazz.getSimpleName());
+ for (Method method : clazz.getDeclaredMethods()) {
+ if (Modifier.isPublic(method.getModifiers())) {
+ eventCategoryTO.getEvents().add(method.getName());
+ }
+ }
+ events.add(eventCategoryTO);
+ }
+ }
+ }
+
+ //SYNCOPE-608
+ final EventCategoryTO authenticationControllerEvents = new EventCategoryTO();
+ authenticationControllerEvents.setCategory("AuthenticationController");
+ authenticationControllerEvents.getEvents().add("login");
+ events.add(authenticationControllerEvents);
+
+ events.add(new EventCategoryTO(EventCategoryType.PROPAGATION));
+ events.add(new EventCategoryTO(EventCategoryType.SYNCHRONIZATION));
+ events.add(new EventCategoryTO(EventCategoryType.PUSH));
+
+ for (AttributableType attributableType : AttributableType.values()) {
+ for (ExternalResource resource : resourceDAO.findAll()) {
+ final EventCategoryTO propEventCategoryTO = new EventCategoryTO(EventCategoryType.PROPAGATION);
+ final EventCategoryTO syncEventCategoryTO = new EventCategoryTO(EventCategoryType.SYNCHRONIZATION);
+ final EventCategoryTO pushEventCategoryTO = new EventCategoryTO(EventCategoryType.PUSH);
+
+ propEventCategoryTO.setCategory(attributableType.name().toLowerCase());
+ propEventCategoryTO.setSubcategory(resource.getKey());
+
+ syncEventCategoryTO.setCategory(attributableType.name().toLowerCase());
+ pushEventCategoryTO.setCategory(attributableType.name().toLowerCase());
+ syncEventCategoryTO.setSubcategory(resource.getKey());
+ pushEventCategoryTO.setSubcategory(resource.getKey());
+
+ for (ResourceOperation resourceOperation : ResourceOperation.values()) {
+ propEventCategoryTO.getEvents().add(resourceOperation.name().toLowerCase());
+ syncEventCategoryTO.getEvents().add(resourceOperation.name().toLowerCase());
+ pushEventCategoryTO.getEvents().add(resourceOperation.name().toLowerCase());
+ }
+
+ events.add(propEventCategoryTO);
+ events.add(syncEventCategoryTO);
+ events.add(pushEventCategoryTO);
+ }
+ }
+
+ for (SchedTask task : taskDAO.<SchedTask>findAll(TaskType.SCHEDULED)) {
+ final EventCategoryTO eventCategoryTO = new EventCategoryTO(EventCategoryType.TASK);
+ eventCategoryTO.setCategory(Class.forName(task.getJobClassName()).getSimpleName());
+ events.add(eventCategoryTO);
+ }
+
+ for (SyncTask task : taskDAO.<SyncTask>findAll(TaskType.SYNCHRONIZATION)) {
+ final EventCategoryTO eventCategoryTO = new EventCategoryTO(EventCategoryType.TASK);
+ eventCategoryTO.setCategory(Class.forName(task.getJobClassName()).getSimpleName());
+ events.add(eventCategoryTO);
+ }
+ } catch (Exception e) {
+ LOG.error("Failure retrieving audit/notification events", e);
+ }
+
+ return new ArrayList<EventCategoryTO>(events);
+ }
+
+ @Override
+ protected LoggerTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/LogicInvocationHandler.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/LogicInvocationHandler.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/LogicInvocationHandler.java
new file mode 100644
index 0000000..81ca56f
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/LogicInvocationHandler.java
@@ -0,0 +1,108 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.server.logic.audit.AuditManager;
+import org.apache.syncope.server.logic.notification.NotificationManager;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+@Aspect
+public class LogicInvocationHandler {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(LogicInvocationHandler.class);
+
+ @Autowired
+ private NotificationManager notificationManager;
+
+ @Autowired
+ private AuditManager auditManager;
+
+ @Around("execution(* org.apache.syncope.server.logic.AbstractLogic+.*(..))")
+ public Object around(final ProceedingJoinPoint joinPoint) throws Throwable {
+ final Class<?> clazz = joinPoint.getTarget().getClass();
+
+ final Object[] input = joinPoint.getArgs();
+
+ final String category = clazz.getSimpleName();
+
+ final MethodSignature ms = (MethodSignature) joinPoint.getSignature();
+ Method method = ms.getMethod();
+
+ final String event = joinPoint.getSignature().getName();
+
+ AuditElements.Result result = null;
+ Object output = null;
+ Object before = null;
+
+ try {
+ LOG.debug("Before {}.{}({})", clazz.getSimpleName(), event,
+ input == null || input.length == 0 ? "" : Arrays.asList(input));
+
+ try {
+ before = ((AbstractLogic) joinPoint.getTarget()).resolveBeanReference(method, input);
+ } catch (UnresolvedReferenceException ignore) {
+ LOG.debug("Unresolved bean reference ...");
+ }
+
+ output = joinPoint.proceed();
+ result = AuditElements.Result.SUCCESS;
+
+ LOG.debug("After returning {}.{}: {}", clazz.getSimpleName(), event, output);
+ return output;
+ } catch (Throwable t) {
+ output = t;
+ result = AuditElements.Result.FAILURE;
+
+ LOG.debug("After throwing {}.{}", clazz.getSimpleName(), event);
+ throw t;
+ } finally {
+ notificationManager.createTasks(
+ AuditElements.EventCategoryType.REST,
+ category,
+ null,
+ event,
+ result,
+ before,
+ output,
+ input);
+
+ auditManager.audit(
+ AuditElements.EventCategoryType.REST,
+ category,
+ null,
+ event,
+ result,
+ before,
+ output,
+ input);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/NotificationController.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/NotificationController.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/NotificationController.java
new file mode 100644
index 0000000..053cf3f
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/NotificationController.java
@@ -0,0 +1,127 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.to.NotificationTO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.NotificationDAO;
+import org.apache.syncope.persistence.api.entity.Notification;
+import org.apache.syncope.server.logic.data.NotificationDataBinder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+@Component
+public class NotificationController extends AbstractTransactionalLogic<NotificationTO> {
+
+ @Autowired
+ private NotificationDAO notificationDAO;
+
+ @Autowired
+ private NotificationDataBinder binder;
+
+ @PreAuthorize("hasRole('NOTIFICATION_READ')")
+ public NotificationTO read(final Long notificationId) {
+ Notification notification = notificationDAO.find(notificationId);
+ if (notification == null) {
+ LOG.error("Could not find notification '" + notificationId + "'");
+
+ throw new NotFoundException(String.valueOf(notificationId));
+ }
+
+ return binder.getNotificationTO(notification);
+ }
+
+ @PreAuthorize("hasRole('NOTIFICATION_LIST')")
+ public List<NotificationTO> list() {
+ List<Notification> notifications = notificationDAO.findAll();
+
+ List<NotificationTO> notificationTOs = new ArrayList<NotificationTO>();
+ for (Notification notification : notifications) {
+ notificationTOs.add(binder.getNotificationTO(notification));
+ }
+
+ return notificationTOs;
+ }
+
+ @PreAuthorize("hasRole('NOTIFICATION_CREATE')")
+ public NotificationTO create(final NotificationTO notificationTO) {
+ return binder.getNotificationTO(notificationDAO.save(binder.create(notificationTO)));
+ }
+
+ @PreAuthorize("hasRole('NOTIFICATION_UPDATE')")
+ public NotificationTO update(final NotificationTO notificationTO) {
+ Notification notification = notificationDAO.find(notificationTO.getKey());
+ if (notification == null) {
+ LOG.error("Could not find notification '" + notificationTO.getKey() + "'");
+ throw new NotFoundException(String.valueOf(notificationTO.getKey()));
+ }
+
+ binder.update(notification, notificationTO);
+ notification = notificationDAO.save(notification);
+
+ return binder.getNotificationTO(notification);
+ }
+
+ @PreAuthorize("hasRole('CONNECTOR_DELETE')")
+ public NotificationTO delete(final Long notificationId) {
+ Notification notification = notificationDAO.find(notificationId);
+ if (notification == null) {
+ LOG.error("Could not find notification '" + notificationId + "'");
+
+ throw new NotFoundException(String.valueOf(notificationId));
+ }
+
+ NotificationTO deleted = binder.getNotificationTO(notification);
+ notificationDAO.delete(notificationId);
+ return deleted;
+ }
+
+ @Override
+ protected NotificationTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ Long id = null;
+
+ if (ArrayUtils.isNotEmpty(args)) {
+ for (int i = 0; id == null && i < args.length; i++) {
+ if (args[i] instanceof Long) {
+ id = (Long) args[i];
+ } else if (args[i] instanceof NotificationTO) {
+ id = ((NotificationTO) args[i]).getKey();
+ }
+ }
+ }
+
+ if ((id != null) && !id.equals(0l)) {
+ try {
+ return binder.getNotificationTO(notificationDAO.find(id));
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
[03/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/resources/content.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/resources/content.xml b/syncope620/server/persistence-jpa/src/test/resources/content.xml
index 4f024e0..04ee462 100644
--- a/syncope620/server/persistence-jpa/src/test/resources/content.xml
+++ b/syncope620/server/persistence-jpa/src/test/resources/content.xml
@@ -143,7 +143,7 @@ under the License.
creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
<SyncopeRole id="6"
name="director" parent_id="4" userOwner_id="5"
- inheritAttrs="1" inheritDerAttrs="1" inheritVirAttrs="1"
+ inheritPlainAttrs="1" inheritDerAttrs="1" inheritVirAttrs="1"
inheritPasswordPolicy="0" inheritAccountPolicy="0"
passwordPolicy_id="4"
accountPolicy_id="6"
@@ -151,7 +151,7 @@ under the License.
creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
<SyncopeRole id="7"
name="managingDirector" parent_id="6"
- inheritAttrs="1" inheritDerAttrs="1" inheritVirAttrs="1"
+ inheritPlainAttrs="1" inheritDerAttrs="1" inheritVirAttrs="1"
inheritPasswordPolicy="1" inheritAccountPolicy="1" inheritOwner="1"
creator="admin" lastModifier="admin"
creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
@@ -166,7 +166,7 @@ under the License.
creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
<SyncopeRole id="10"
name="managingConsultant" parent_id="6"
- inheritAttrs="1" inheritDerAttrs="1" inheritVirAttrs="1"
+ inheritPlainAttrs="1" inheritDerAttrs="1" inheritVirAttrs="1"
inheritPasswordPolicy="1" inheritAccountPolicy="1" inheritOwner="0"
creator="admin" lastModifier="admin"
creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
@@ -181,7 +181,7 @@ under the License.
creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
<SyncopeRole id="14"
name="artDirector" parent_id="4"
- inheritAttrs="1" inheritDerAttrs="1" inheritVirAttrs="1"
+ inheritPlainAttrs="1" inheritDerAttrs="1" inheritVirAttrs="1"
inheritPasswordPolicy="0" inheritAccountPolicy="0"
passwordPolicy_id="8"
accountPolicy_id="6"
@@ -904,8 +904,8 @@ under the License.
<Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="4" name="CSV (update matching; assign unmatching)" resource_name="resource-csv"
performCreate="1" performUpdate="1" performDelete="1" syncStatus="1" fullReconciliation="0"
jobClassName="org.apache.syncope.provisioning.api.job.SyncJob" unmatchingRule="ASSIGN" matchingRule="UPDATE"
- userTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"id":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"attributes":[{"schema":"type","readonly":false,"values":["email == 'test8@syncope.apache.org'? 'TYPE_8': 'TYPE_OTHER'"]}],"derivedAttributes":[{"schema":"cn","readonly":false,"values":[null]}],"virtualAttributes":[],"resources":["resource-testdb"],"propagationStatuses":[],"memberships":[{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"id":0,"roleId":8,"roleName":null,"attributes":[{"schema":"subscriptionDate","readonly":false,"values":["'2009-08-18T16:33:12.203+0200'"]}],"derivedAttributes":[],"virtualAttributes":[]}]}'
- roleTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"id":0,"name":null,"parent":0,"userOwner":null,"roleOwner":null,"inheritOwner":false,"inheritTemplates":false,"inheritAttrs":false,"inheritDerAttrs":false,"inheritVirAttrs":false,"inheritPasswordPolicy":false,"inheritAccountPolicy":false,"passwordPolicy":null,"accountPolicy":null,"attributes":[],"derivedAttributes":[],"virtualAttributes":[],"resources":[],"propagationStatuses":[],"entitlements":[],"rAttrTemplates":[],"rDerAttrTemplates":[],"rVirAttrTemplates":[],"mAttrTemplates":[],"mDerAttrTemplates":[],"mVirAttrTemplates":[]}'/>
+ userTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"attributes":[{"schema":"type","readonly":false,"values":["email == 'test8@syncope.apache.org'? 'TYPE_8': 'TYPE_OTHER'"]}],"derivedAttributes":[{"schema":"cn","readonly":false,"values":[null]}],"virtualAttributes":[],"resources":["resource-testdb"],"propagationStatuses":[],"memberships":[{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"id":0,"roleId":8,"roleName":null,"attributes":[{"schema":"subscriptionDate","readonly":false,"values":["'2009-08-18T16:33:12.203+0200'"]}],"derivedAttributes":[],"virtualAttributes":[]}]}'
+ roleTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"name":null,"parent":0,"userOwner":null,"roleOwner":null,"inheritOwner":false,"inheritTemplates":false,"inheritPlainAttrs":false,"inheritDerAttrs":false,"inheritVirAttrs":false,"inheritPasswordPolicy":false,"inheritAccountPolicy":false,"passwordPolicy":null,"accountPolicy":null,"attributes":[],"derivedAttributes":[],"virtualAttributes":[],"resources":[],"propagationStatuses":[],"entitlements":[],"rAttrTemplates":[],"rDerAttrTemplates":[],"rVirAttrTemplates":[],"mAttrTemplates":[],"mDerAttrTemplates":[],"mVirAttrTemplates":[]}'/>
<Task DTYPE="SchedTask" type="SCHEDULED" id="5" name="SampleJob Task" jobClassName="org.apache.syncope.core.quartz.SampleJob" cronExpression="0 0 0 1 * ?"/>
<Task DTYPE="PropagationTask" type="PROPAGATION" id="6" propagationMode="TWO_PHASES" propagationOperation="UPDATE"
objectClassName="__ACCOUNT__" resource_name="ws-target-resource-nopropagation" subjectType="USER" subjectId="1"
@@ -914,8 +914,8 @@ under the License.
<Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="7" name="TestDB Task" resource_name="resource-testdb"
performCreate="1" performUpdate="1" performDelete="0" syncStatus="1" fullReconciliation="1"
jobClassName="org.apache.syncope.provisioning.api.job.SyncJob" unmatchingRule="PROVISION" matchingRule="UPDATE"
- userTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"id":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"attributes":[{"schema":"type","readonly":false,"values":["'type a'"]},{"schema":"userId","readonly":false,"values":["'reconciled@syncope.apache.org'"]},{"schema":"fullname","readonly":false,"values":["'reconciled fullname'"]},{"schema":"surname","readonly":false,"values":["'surname'"]}],"derivedAttributes":[],"virtualAttributes":[],"resources":[],"propagationStatuses":[],"memberships":[]}'
- roleTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"id":0,"name":null,"parent":0,"userOwner":null,"roleOwner":null,"inheritOwner":false,"inheritTemplates":false,"inheritAttrs":false,"inheritDerAttrs":false,"inheritVirAttrs":false,"inheritPasswordPolicy":false,"inheritAccountPolicy":false,"passwordPolicy":null,"accountPolicy":null,"attributes":[],"derivedAttributes":[],"virtualAttributes":[],"resources":[],"propagationStatuses":[],"entitlements":[],"rAttrTemplates":[],"rDerAttrTemplates":[],"rVirAttrTemplates":[],"mAttrTemplates":[],"mDerAttrTemplates":[],"mVirAttrTemplates":[]}'/>
+ userTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"attributes":[{"schema":"type","readonly":false,"values":["'type a'"]},{"schema":"userId","readonly":false,"values":["'reconciled@syncope.apache.org'"]},{"schema":"fullname","readonly":false,"values":["'reconciled fullname'"]},{"schema":"surname","readonly":false,"values":["'surname'"]}],"derivedAttributes":[],"virtualAttributes":[],"resources":[],"propagationStatuses":[],"memberships":[]}'
+ roleTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"name":null,"parent":0,"userOwner":null,"roleOwner":null,"inheritOwner":false,"inheritTemplates":false,"inheritPlainAttrs":false,"inheritDerAttrs":false,"inheritVirAttrs":false,"inheritPasswordPolicy":false,"inheritAccountPolicy":false,"passwordPolicy":null,"accountPolicy":null,"attributes":[],"derivedAttributes":[],"virtualAttributes":[],"resources":[],"propagationStatuses":[],"entitlements":[],"rAttrTemplates":[],"rDerAttrTemplates":[],"rVirAttrTemplates":[],"mAttrTemplates":[],"mDerAttrTemplates":[],"mVirAttrTemplates":[]}'/>
<Task DTYPE="NotificationTask" type="NOTIFICATION" id="8" sender="admin@prova.org" subject="Notification for SYNCOPE-81"
textBody="NOTIFICATION-81" htmlBody="NOTIFICATION-81" traceLevel="ALL"/>
<Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="9" name="TestDB2 Task" resource_name="resource-testdb2"
@@ -927,8 +927,8 @@ under the License.
<Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="11" name="LDAP Sync Task" resource_name="resource-ldap"
fullReconciliation="1" performCreate="1" performDelete="1" performUpdate="1" syncStatus="0"
jobClassName="org.apache.syncope.provisioning.api.job.SyncJob" unmatchingRule="PROVISION" matchingRule="UPDATE"
- userTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"id":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"attributes":[],"derivedAttributes":[],"virtualAttributes":[{"schema":"virtualReadOnly","readonly":false,"values":[""]}],"resources":["resource-ldap"],"propagationStatuses":[],"memberships":[]}'
- roleTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"id":0,"name":null,"parent":8,"userOwner":null,"roleOwner":null,"inheritOwner":false,"inheritTemplates":false,"inheritAttrs":false,"inheritDerAttrs":false,"inheritVirAttrs":false,"inheritPasswordPolicy":false,"inheritAccountPolicy":false,"passwordPolicy":null,"accountPolicy":null,"attributes":[{"schema":"show","readonly":false,"values":["'true'"]}],"derivedAttributes":[],"virtualAttributes":[],"resources":[],"propagationStatuses":[],"entitlements":[],"rAttrTemplates":["show"],"rDerAttrTemplates":[],"rVirAttrTemplates":[],"mAttrTemplates":[],"mDerAttrTemplates":[],"mVirAttrTemplates":[]}'/>
+ userTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"attributes":[],"derivedAttributes":[],"virtualAttributes":[{"schema":"virtualReadOnly","readonly":false,"values":[""]}],"resources":["resource-ldap"],"propagationStatuses":[],"memberships":[]}'
+ roleTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"name":null,"parent":8,"userOwner":null,"roleOwner":null,"inheritOwner":false,"inheritTemplates":false,"inheritPlainAttrs":false,"inheritDerAttrs":false,"inheritVirAttrs":false,"inheritPasswordPolicy":false,"inheritAccountPolicy":false,"passwordPolicy":null,"accountPolicy":null,"attributes":[{"schema":"show","readonly":false,"values":["'true'"]}],"derivedAttributes":[],"virtualAttributes":[],"resources":[],"propagationStatuses":[],"entitlements":[],"rAttrTemplates":["show"],"rDerAttrTemplates":[],"rVirAttrTemplates":[],"mAttrTemplates":[],"mDerAttrTemplates":[],"mVirAttrTemplates":[]}'/>
<SyncTask_actionsClassNames SyncTask_id="11" actionClassName="org.apache.syncope.core.sync.impl.LDAPMembershipSyncActions"/>
<Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="12" name="VirAttrCache test" resource_name="resource-csv"
performCreate="0" performUpdate="1" performDelete="0" syncStatus="0" fullReconciliation="1"
@@ -980,8 +980,8 @@ under the License.
<Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="24" name="CSV Task (update matching; provision unmatching)" resource_name="resource-csv"
performCreate="1" performUpdate="1" performDelete="1" syncStatus="1" fullReconciliation="0"
jobClassName="org.apache.syncope.provisioning.api.job.SyncJob" unmatchingRule="PROVISION" matchingRule="UPDATE"
- userTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"id":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"attributes":[{"schema":"firstname","readonly":false,"values":[""]},{"schema":"userId","readonly":false,"values":["'test'"]},{"schema":"fullname","readonly":false,"values":["'test'"]},{"schema":"surname","readonly":false,"values":["'test'"]}],"derivedAttributes":[],"virtualAttributes":[],"resources":["resource-testdb"],"propagationStatuses":[],"memberships":[]}'
- roleTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"id":0,"name":null,"parent":0,"userOwner":null,"roleOwner":null,"inheritOwner":false,"inheritTemplates":false,"inheritAttrs":false,"inheritDerAttrs":false,"inheritVirAttrs":false,"inheritPasswordPolicy":false,"inheritAccountPolicy":false,"passwordPolicy":null,"accountPolicy":null,"attributes":[],"derivedAttributes":[],"virtualAttributes":[],"resources":[],"propagationStatuses":[],"entitlements":[],"rAttrTemplates":[],"rDerAttrTemplates":[],"rVirAttrTemplates":[],"mAttrTemplates":[],"mDerAttrTemplates":[],"mVirAttrTemplates":[]}'/>
+ userTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"password":null,"status":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"attributes":[{"schema":"firstname","readonly":false,"values":[""]},{"schema":"userId","readonly":false,"values":["'test'"]},{"schema":"fullname","readonly":false,"values":["'test'"]},{"schema":"surname","readonly":false,"values":["'test'"]}],"derivedAttributes":[],"virtualAttributes":[],"resources":["resource-testdb"],"propagationStatuses":[],"memberships":[]}'
+ roleTemplate='{"creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":0,"name":null,"parent":0,"userOwner":null,"roleOwner":null,"inheritOwner":false,"inheritTemplates":false,"inheritPlainAttrs":false,"inheritDerAttrs":false,"inheritVirAttrs":false,"inheritPasswordPolicy":false,"inheritAccountPolicy":false,"passwordPolicy":null,"accountPolicy":null,"attributes":[],"derivedAttributes":[],"virtualAttributes":[],"resources":[],"propagationStatuses":[],"entitlements":[],"rAttrTemplates":[],"rDerAttrTemplates":[],"rVirAttrTemplates":[],"mAttrTemplates":[],"mDerAttrTemplates":[],"mVirAttrTemplates":[]}'/>
<Task DTYPE="SyncTask" type="SYNCHRONIZATION" id="25" name="CSV (unlink matching; ignore unmatching)" resource_name="resource-csv"
performCreate="1" performUpdate="1" performDelete="1" syncStatus="1" fullReconciliation="0"
jobClassName="org.apache.syncope.provisioning.api.job.SyncJob" unmatchingRule="IGNORE" matchingRule="UNLINK"/>
@@ -1011,7 +1011,7 @@ under the License.
<Report id="1" name="test"/>
<ReportletConfInstance id="1" Report_id="1"
- serializedInstance='{"@class":"org.apache.syncope.common.lib.report.UserReportletConf","name":"testUserReportlet","matchingCond":null,"attributes":["fullname","gender"],"derivedAttributes":["cn"],"virtualAttributes":["virtualdata"],"features":["id","username","workflowId","status","creationDate","lastLoginDate","changePwdDate","passwordHistorySize","failedLoginCount","memberships","resources"]}'/>
+ serializedInstance='{"@class":"org.apache.syncope.common.lib.report.UserReportletConf","name":"testUserReportlet","matchingCond":null,"attributes":["fullname","gender"],"derivedAttributes":["cn"],"virtualAttributes":["virtualdata"],"features":["key","username","workflowId","status","creationDate","lastLoginDate","changePwdDate","passwordHistorySize","failedLoginCount","memberships","resources"]}'/>
<ReportExec Report_id="1" id="1" status="SUCCESS" startDate="2012-02-26 15:40:04" endDate="2012-02-26 15:41:04"/>
<SyncopeLogger logName="syncope.audit.[REST]:[EntitlementController]:[]:[getOwn]:[SUCCESS]" logLevel="DEBUG" logType="AUDIT"/>
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/resources/persistenceTestEnv.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/resources/persistenceTestEnv.xml b/syncope620/server/persistence-jpa/src/test/resources/persistenceTestEnv.xml
index 53bc496..0170569 100644
--- a/syncope620/server/persistence-jpa/src/test/resources/persistenceTestEnv.xml
+++ b/syncope620/server/persistence-jpa/src/test/resources/persistenceTestEnv.xml
@@ -45,5 +45,10 @@ under the License.
<context:component-scan base-package="org.apache.syncope.server.utils"/>
+ <bean id="virAttrCache" class="org.apache.syncope.provisioning.common.cache.MemoryVirAttrCache" scope="singleton">
+ <constructor-arg value="60"/>
+ <constructor-arg value="5000"/>
+ </bean>
+
<import resource="persistenceContext.xml"/>
</beans>
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/pom.xml
----------------------------------------------------------------------
diff --git a/syncope620/server/pom.xml b/syncope620/server/pom.xml
index fe6c089..19a959b 100644
--- a/syncope620/server/pom.xml
+++ b/syncope620/server/pom.xml
@@ -34,12 +34,15 @@ under the License.
<packaging>pom</packaging>
<modules>
- <module>provisioning-api</module>
<module>persistence-api</module>
<module>persistence-jpa</module>
<module>spring</module>
<module>security</module>
<module>utils</module>
+ <module>provisioning-api</module>
+ <module>provisioning-common</module>
+ <module>workflow-api</module>
+ <module>logic</module>
</modules>
</project>
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/AttributableTransformer.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/AttributableTransformer.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/AttributableTransformer.java
new file mode 100644
index 0000000..b1f39f9
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/AttributableTransformer.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.provisioning.api;
+
+import org.apache.syncope.common.lib.mod.AbstractAttributableMod;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+
+/**
+ * Provides logic for transforming user or role, received as input by RESTful methods, before any internal
+ * processing logic takes place.
+ */
+public interface AttributableTransformer {
+
+ <T extends AbstractAttributableTO> T transform(T input);
+
+ <T extends AbstractAttributableMod> T transform(T input);
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/ConnIdBundleManager.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/ConnIdBundleManager.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/ConnIdBundleManager.java
new file mode 100644
index 0000000..bf07215
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/ConnIdBundleManager.java
@@ -0,0 +1,284 @@
+/*
+ * 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.provisioning.api;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URL;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.identityconnectors.common.IOUtil;
+import org.identityconnectors.common.security.GuardedString;
+import org.identityconnectors.framework.api.APIConfiguration;
+import org.identityconnectors.framework.api.ConfigurationProperties;
+import org.identityconnectors.framework.api.ConnectorInfo;
+import org.identityconnectors.framework.api.ConnectorInfoManager;
+import org.identityconnectors.framework.api.ConnectorInfoManagerFactory;
+import org.identityconnectors.framework.api.ConnectorKey;
+import org.identityconnectors.framework.api.RemoteFrameworkConnectionInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Manage information about ConnId connector bundles.
+ */
+public class ConnIdBundleManager {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConnIdBundleManager.class);
+
+ private String stringLocations;
+
+ /**
+ * ConnId Locations.
+ */
+ private List<URI> locations;
+
+ /**
+ * ConnectorInfoManager instances.
+ */
+ private final Map<URI, ConnectorInfoManager> connInfoManagers =
+ Collections.synchronizedMap(new LinkedHashMap<URI, ConnectorInfoManager>());
+
+ public void setStringLocations(final String stringLocations) {
+ this.stringLocations = stringLocations;
+ }
+
+ private void init() {
+ if (locations == null) {
+ locations = new ArrayList<>();
+ for (String location : StringUtils.isBlank(stringLocations) ? new String[0] : stringLocations.split(",")) {
+ try {
+ locations.add(URIUtil.buildForConnId(location));
+ LOG.info("Valid ConnId location: {}", location.trim());
+ } catch (Exception e) {
+ LOG.error("Invalid ConnId location: {}", location.trim(), e);
+ }
+ }
+ locations = Collections.unmodifiableList(locations);
+ }
+ }
+
+ private void initLocal(final URI location) {
+ // 1. Find bundles inside local directory
+ File bundleDirectory = new File(location);
+ String[] bundleFiles = bundleDirectory.list();
+ if (bundleFiles == null) {
+ throw new NotFoundException("Local bundles directory " + location);
+ }
+
+ List<URL> bundleFileURLs = new ArrayList<>();
+ for (String file : bundleFiles) {
+ try {
+ bundleFileURLs.add(IOUtil.makeURL(bundleDirectory, file));
+ } catch (IOException ignore) {
+ // ignore exception and don't add bundle
+ LOG.debug("{}/{} is not a valid connector bundle", bundleDirectory.toString(), file, ignore);
+ }
+ }
+
+ if (bundleFileURLs.isEmpty()) {
+ LOG.warn("No connector bundles found in {}", location);
+ }
+ LOG.debug("Configuring local connector server:"
+ + "\n\tFiles: {}", bundleFileURLs);
+
+ // 2. Get connector info manager
+ ConnectorInfoManager manager = ConnectorInfoManagerFactory.getInstance().getLocalManager(
+ bundleFileURLs.toArray(new URL[bundleFileURLs.size()]));
+ if (manager == null) {
+ throw new NotFoundException("Local ConnectorInfoManager");
+ }
+
+ connInfoManagers.put(location, manager);
+ }
+
+ private void initRemote(final URI location) {
+ // 1. Extract conf params for remote connection from given URI
+ final String host = location.getHost();
+ final int port = location.getPort();
+ final GuardedString key = new GuardedString(location.getUserInfo().toCharArray());
+ final boolean useSSL = location.getScheme().equals("connids");
+
+ final List<TrustManager> trustManagers = new ArrayList<>();
+ final String[] params = StringUtils.isBlank(location.getQuery()) ? null : location.getQuery().split("&");
+ if (params != null && params.length > 0) {
+ final String[] trustAllCerts = params[0].split("=");
+ if (trustAllCerts != null && trustAllCerts.length > 1
+ && "trustAllCerts".equalsIgnoreCase(trustAllCerts[0])
+ && "true".equalsIgnoreCase(trustAllCerts[1])) {
+
+ trustManagers.add(new X509TrustManager() {
+
+ @Override
+ public void checkClientTrusted(final X509Certificate[] chain, final String authType)
+ throws CertificateException {
+ // no checks, trust all
+ }
+
+ @Override
+ public void checkServerTrusted(final X509Certificate[] chain, final String authType)
+ throws CertificateException {
+ // no checks, trust all
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+ });
+ }
+ }
+
+ LOG.debug("Configuring remote connector server:"
+ + "\n\tHost: {}"
+ + "\n\tPort: {}"
+ + "\n\tKey: {}"
+ + "\n\tUseSSL: {}"
+ + "\n\tTrustAllCerts: {}",
+ host, port, key, useSSL, !trustManagers.isEmpty());
+
+ RemoteFrameworkConnectionInfo info =
+ new RemoteFrameworkConnectionInfo(host, port, key, useSSL, trustManagers, 60 * 1000);
+ LOG.debug("Remote connection info: {}", info);
+
+ // 2. Get connector info manager
+ ConnectorInfoManager manager = ConnectorInfoManagerFactory.getInstance().getRemoteManager(info);
+ if (manager == null) {
+ throw new NotFoundException("Remote ConnectorInfoManager");
+ }
+
+ connInfoManagers.put(location, manager);
+ }
+
+ public void resetConnManagers() {
+ connInfoManagers.clear();
+ }
+
+ public Map<URI, ConnectorInfoManager> getConnManagers() {
+ init();
+
+ if (connInfoManagers.isEmpty()) {
+ for (URI location : locations) {
+ try {
+ if ("file".equals(location.getScheme())) {
+ LOG.debug("Local initialization: {}", location);
+ initLocal(location);
+ } else if (location.getScheme().startsWith("connid")) {
+ LOG.debug("Remote initialization: {}", location);
+ initRemote(location);
+ } else {
+ LOG.warn("Unsupported scheme: {}", location);
+ }
+ } catch (Exception e) {
+ LOG.error("Could not process {}", location, e);
+ }
+ }
+ }
+
+ if (LOG.isDebugEnabled()) {
+ for (Map.Entry<URI, ConnectorInfoManager> entry : connInfoManagers.entrySet()) {
+ LOG.debug("Connector bundles found at {}", entry.getKey());
+ for (ConnectorInfo connInfo : entry.getValue().getConnectorInfos()) {
+ LOG.debug("\t{}", connInfo.getConnectorDisplayName());
+ }
+ }
+ }
+
+ return connInfoManagers;
+ }
+
+ public ConnectorInfo getConnectorInfo(
+ final String location, final String bundleName, final String bundleVersion, final String connectorName) {
+
+ // check ConnIdLocation
+ URI uriLocation = null;
+ try {
+ uriLocation = URIUtil.buildForConnId(location);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Invalid ConnId location " + location, e);
+ }
+
+ // create key for search all properties
+ final ConnectorKey key = new ConnectorKey(bundleName, bundleVersion, connectorName);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("\nBundle name: " + key.getBundleName()
+ + "\nBundle version: " + key.getBundleVersion()
+ + "\nBundle class: " + key.getConnectorName());
+ }
+
+ // get the specified connector
+ ConnectorInfo info = null;
+ if (getConnManagers().containsKey(uriLocation)) {
+ info = getConnManagers().get(uriLocation).findConnectorInfo(key);
+ }
+ if (info == null) {
+ throw new NotFoundException("Connector Info for location " + location + " and key " + key);
+ }
+
+ return info;
+ }
+
+ public Map<String, List<ConnectorInfo>> getConnectorInfos() {
+ final Map<String, List<ConnectorInfo>> infos = new LinkedHashMap<>();
+ for (Map.Entry<URI, ConnectorInfoManager> entry : connInfoManagers.entrySet()) {
+ infos.put(entry.getKey().toString(), entry.getValue().getConnectorInfos());
+ }
+ return infos;
+ }
+
+ public ConfigurationProperties getConfigurationProperties(final ConnectorInfo info) {
+ if (info == null) {
+ throw new NotFoundException("Invalid: connector info is null");
+ }
+
+ // create default configuration
+ final APIConfiguration apiConfig = info.createDefaultAPIConfiguration();
+ if (apiConfig == null) {
+ throw new NotFoundException("Default API configuration");
+ }
+
+ // retrieve the ConfigurationProperties.
+ final ConfigurationProperties properties = apiConfig.getConfigurationProperties();
+ if (properties == null) {
+ throw new NotFoundException("Configuration properties");
+ }
+
+ if (LOG.isDebugEnabled()) {
+ for (String propName : properties.getPropertyNames()) {
+ LOG.debug("Property Name: {}"
+ + "\nProperty Type: {}",
+ properties.getProperty(propName).getName(),
+ properties.getProperty(propName).getType());
+ }
+ }
+
+ return properties;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/ProvisioningManager.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/ProvisioningManager.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/ProvisioningManager.java
new file mode 100644
index 0000000..66f5e73
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/ProvisioningManager.java
@@ -0,0 +1,42 @@
+/*
+ * 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.provisioning.api;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import org.apache.syncope.common.lib.mod.AbstractAttributableMod;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+
+public interface ProvisioningManager<T extends AbstractAttributableTO, M extends AbstractAttributableMod> {
+
+ Map.Entry<Long, List<PropagationStatus>> create(T subject);
+
+ Map.Entry<Long, List<PropagationStatus>> update(M subjectMod);
+
+ List<PropagationStatus> delete(Long subjectId);
+
+ Long unlink(M subjectMod);
+
+ Long link(M subjectMod);
+
+ List<PropagationStatus> deprovision(Long user, Collection<String> resources);
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/RoleProvisioningManager.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/RoleProvisioningManager.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/RoleProvisioningManager.java
new file mode 100644
index 0000000..822981b
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/RoleProvisioningManager.java
@@ -0,0 +1,37 @@
+/*
+ * 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.provisioning.api;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.RoleTO;
+
+public interface RoleProvisioningManager extends ProvisioningManager<RoleTO, RoleMod> {
+
+ Map.Entry<Long, List<PropagationStatus>> create(RoleTO roleTO, Set<String> excludedResources);
+
+ Map.Entry<Long, List<PropagationStatus>> create(
+ RoleTO roleTO, Map<Long, String> roleOwnerMap, Set<String> excludedResources);
+
+ Map.Entry<Long, List<PropagationStatus>> update(RoleMod subjectMod, Set<String> excludedResources);
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/URIUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/URIUtil.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/URIUtil.java
new file mode 100644
index 0000000..f8fd111
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/URIUtil.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.provisioning.api;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+public final class URIUtil {
+
+ private URIUtil() {
+ // empty constructor for static utility class
+ }
+
+ /**
+ * Build a valid URI out of the given location.
+ * Only "file", "connid" and "connids" schemes are allowed.
+ * For "file", invalid characters are handled via intermediate transformation into URL.
+ *
+ * @param location the candidate location for URI
+ * @return valid URI for the given location
+ * @throws MalformedURLException if the intermediate URL is not valid
+ * @throws URISyntaxException if the given location does not correspond to a valid URI
+ */
+ public static URI buildForConnId(final String location) throws MalformedURLException, URISyntaxException {
+ final String candidate = location.trim();
+
+ if (!candidate.startsWith("file:")
+ && !candidate.startsWith("connid:") && !candidate.startsWith("connids:")) {
+
+ throw new IllegalArgumentException(candidate + " is not a valid URI for file or connid(s) schemes");
+ }
+
+ URI uri;
+ if (candidate.startsWith("file:")) {
+ uri = new File(new URL(candidate).getFile()).getAbsoluteFile().toURI();
+ } else {
+ uri = new URI(candidate);
+ }
+
+ return uri;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/UserProvisioningManager.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/UserProvisioningManager.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/UserProvisioningManager.java
new file mode 100644
index 0000000..b686127
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/UserProvisioningManager.java
@@ -0,0 +1,57 @@
+/*
+ * 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.provisioning.api;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.lib.mod.StatusMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.provisioning.api.sync.SyncResult;
+
+public interface UserProvisioningManager extends ProvisioningManager<UserTO, UserMod> {
+
+ Map.Entry<Long, List<PropagationStatus>> activate(User user, StatusMod statusMod);
+
+ Map.Entry<Long, List<PropagationStatus>> reactivate(User user, StatusMod statusMod);
+
+ Map.Entry<Long, List<PropagationStatus>> suspend(User user, StatusMod statusMod);
+
+ void innerSuspend(User user, boolean propagate);
+
+ Map.Entry<Long, List<PropagationStatus>> create(UserTO userTO, boolean storePassword);
+
+ Map.Entry<Long, List<PropagationStatus>> create(UserTO userTO, boolean storePassword,
+ boolean disablePwdPolicyCheck, Boolean enabled, Set<String> excludedResources);
+
+ Map.Entry<Long, List<PropagationStatus>> update(UserMod userMod, boolean removeMemberships);
+
+ Map.Entry<Long, List<PropagationStatus>> update(UserMod userMod, Long key,
+ SyncResult result, Boolean enabled, Set<String> excludedResources);
+
+ List<PropagationStatus> delete(Long subjectKey, Set<String> excludedResources);
+
+ void requestPasswordReset(Long key);
+
+ void confirmPasswordReset(User user, String token, String password);
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/WorkflowResult.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/WorkflowResult.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/WorkflowResult.java
new file mode 100644
index 0000000..bb80219
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/WorkflowResult.java
@@ -0,0 +1,87 @@
+/*
+ * 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.provisioning.api;
+
+import java.util.Collections;
+import java.util.Set;
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.syncope.provisioning.api.propagation.PropagationByResource;
+
+public class WorkflowResult<T> {
+
+ private T result;
+
+ private PropagationByResource propByRes;
+
+ private Set<String> performedTasks;
+
+ public WorkflowResult(final T result, final PropagationByResource propByRes, final String performedTask) {
+ this.result = result;
+ this.propByRes = propByRes;
+ this.performedTasks = Collections.singleton(performedTask);
+ }
+
+ public WorkflowResult(final T result, final PropagationByResource propByRes, final Set<String> performedTasks) {
+ this.result = result;
+ this.propByRes = propByRes;
+ this.performedTasks = performedTasks;
+ }
+
+ public T getResult() {
+ return result;
+ }
+
+ public void setResult(final T result) {
+ this.result = result;
+ }
+
+ public Set<String> getPerformedTasks() {
+ return performedTasks;
+ }
+
+ public void setPerformedTasks(final Set<String> performedTasks) {
+ this.performedTasks = performedTasks;
+ }
+
+ public PropagationByResource getPropByRes() {
+ return propByRes;
+ }
+
+ public void setPropByRes(final PropagationByResource propByRes) {
+ this.propByRes = propByRes;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return EqualsBuilder.reflectionEquals(this, obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this);
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCache.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCache.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCache.java
new file mode 100644
index 0000000..c4936a5
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCache.java
@@ -0,0 +1,65 @@
+/*
+ * 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.provisioning.api.cache;
+
+import org.apache.syncope.common.lib.types.AttributableType;
+
+/**
+ * Virtual Attribute Value cache.
+ */
+public interface VirAttrCache {
+
+ /**
+ * Force entry expiring.
+ *
+ * @param type user or role
+ * @param id user or role id
+ * @param schemaName virtual attribute schema name
+ */
+ void expire(AttributableType type, Long id, String schemaName);
+
+ /**
+ * Retrieve cached value. Return null in case of virtual attribute not cached.
+ *
+ * @param type user or role
+ * @param id user or role id
+ * @param schemaName virtual attribute schema name.
+ * @return cached values or null if virtual attribute is not cached.
+ */
+ VirAttrCacheValue get(AttributableType type, Long id, String schemaName);
+
+ /**
+ * Cache entry is valid if and only if value exist and it is not expired.
+ *
+ * @param value cache entry value.
+ * @return TRUE if the value is valid; FALSE otherwise.
+ */
+ boolean isValidEntry(VirAttrCacheValue value);
+
+ /**
+ * Cache virtual attribute values.
+ *
+ * @param type user or role
+ * @param id user or role id
+ * @param schemaName virtual attribute name
+ * @param value virtual attribute values
+ */
+ void put(AttributableType type, Long id, String schemaName, VirAttrCacheValue value);
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCacheKey.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCacheKey.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCacheKey.java
new file mode 100644
index 0000000..bdc60db
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCacheKey.java
@@ -0,0 +1,79 @@
+/*
+ * 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.provisioning.api.cache;
+
+import org.apache.commons.lang3.builder.EqualsBuilder;
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.syncope.common.lib.types.AttributableType;
+
+/**
+ * Cache entry key.
+ */
+public class VirAttrCacheKey {
+
+ /**
+ * Subject type.
+ */
+ private final AttributableType type;
+
+ /**
+ * Subject ID.
+ */
+ private final transient Long id;
+
+ /**
+ * Virtual attribute schema name.
+ */
+ private final transient String virSchema;
+
+ public VirAttrCacheKey(final AttributableType type, final Long id, final String virSchema) {
+ this.type = type;
+ this.id = id;
+ this.virSchema = virSchema;
+ }
+
+ public AttributableType getType() {
+ return type;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public String getVirSchema() {
+ return virSchema;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return EqualsBuilder.reflectionEquals(this, obj, true);
+ }
+
+ @Override
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this, true);
+ }
+
+ @Override
+ public String toString() {
+ return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE, true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCacheValue.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCacheValue.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCacheValue.java
new file mode 100644
index 0000000..1ca9965
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/cache/VirAttrCacheValue.java
@@ -0,0 +1,86 @@
+/*
+ * 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.provisioning.api.cache;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Cache entry value.
+ */
+public class VirAttrCacheValue {
+
+ /**
+ * Virtual attribute values.
+ */
+ private final Map<String, Set<String>> values;
+
+ /**
+ * Entry creation date.
+ */
+ private Date creationDate;
+
+ /**
+ * Entry access date.
+ */
+ private Date lastAccessDate;
+
+ public VirAttrCacheValue() {
+ this.creationDate = new Date();
+ this.lastAccessDate = new Date();
+ values = new HashMap<>();
+ }
+
+ public void setResourceValues(final String resourceName, final Set<String> values) {
+ this.values.put(resourceName, values);
+ }
+
+ public Date getCreationDate() {
+ return creationDate;
+ }
+
+ public void forceExpiring() {
+ creationDate = new Date(0);
+ }
+
+ public Set<String> getValues(final String resourceName) {
+ return values.get(resourceName);
+ }
+
+ public Set<String> getValues() {
+ final Set<String> res = new HashSet<>();
+
+ for (Set<String> value : values.values()) {
+ res.addAll(value);
+ }
+
+ return res;
+ }
+
+ public Date getLastAccessDate() {
+ return lastAccessDate;
+ }
+
+ void setLastAccessDate(final Date lastAccessDate) {
+ this.lastAccessDate = lastAccessDate;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationByResource.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationByResource.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationByResource.java
new file mode 100644
index 0000000..e43443e
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationByResource.java
@@ -0,0 +1,365 @@
+/*
+ * 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.provisioning.api.propagation;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+
+/**
+ * Utility class for encapsulating operations to be performed on various resources.
+ */
+public class PropagationByResource implements Serializable {
+
+ private static final long serialVersionUID = -5699740428104336636L;
+
+ /**
+ * Resources for creation.
+ */
+ private final Set<String> toBeCreated;
+
+ /**
+ * Resources for update.
+ */
+ private final Set<String> toBeUpdated;
+
+ /**
+ * Resources for deletion.
+ */
+ private final Set<String> toBeDeleted;
+
+ /**
+ * Mapping target resource names to old account ids (when applicable).
+ */
+ private final Map<String, String> oldAccountIds;
+
+ /**
+ * Default constructor.
+ */
+ public PropagationByResource() {
+ toBeCreated = new HashSet<String>();
+ toBeUpdated = new HashSet<String>();
+ toBeDeleted = new HashSet<String>();
+
+ oldAccountIds = new HashMap<String, String>();
+ }
+
+ /**
+ * Avoid potential conflicts by not doing create or update on any resource for which a delete is requested, and by
+ * not doing any create on any resource for which an update is requested.
+ */
+ public final void purge() {
+ toBeCreated.removeAll(toBeDeleted);
+ toBeCreated.removeAll(toBeUpdated);
+
+ toBeUpdated.removeAll(toBeDeleted);
+ }
+
+ /**
+ * Add an element.
+ *
+ * @param type resource operation type
+ * @param resourceName target resource
+ * @return whether the operation was successful or not
+ */
+ public final boolean add(final ResourceOperation type, final String resourceName) {
+ Set<String> set;
+ switch (type) {
+ case CREATE:
+ set = toBeCreated;
+ break;
+
+ case UPDATE:
+ set = toBeUpdated;
+ break;
+
+ case DELETE:
+ default:
+ set = toBeDeleted;
+ break;
+ }
+
+ return set.add(resourceName);
+ }
+
+ /**
+ * Add some elements.
+ *
+ * @param type resource operation type
+ * @param resourceNames target resources
+ * @return whether the operation was successful or not
+ */
+ public boolean addAll(final ResourceOperation type, final Collection<String> resourceNames) {
+ Set<String> set;
+ switch (type) {
+ case CREATE:
+ set = toBeCreated;
+ break;
+
+ case UPDATE:
+ set = toBeUpdated;
+ break;
+
+ case DELETE:
+ default:
+ set = toBeDeleted;
+ break;
+ }
+
+ return set.addAll(resourceNames);
+ }
+
+ /**
+ * Remove an element.
+ *
+ * @param type resource operation type
+ * @param resourceName target resource
+ * @return whether the operation was successful or not
+ */
+ public final boolean remove(final ResourceOperation type, final String resourceName) {
+ boolean result = false;
+
+ switch (type) {
+ case CREATE:
+ result = toBeCreated.remove(resourceName);
+ break;
+
+ case UPDATE:
+ result = toBeUpdated.remove(resourceName);
+ break;
+
+ case DELETE:
+ result = toBeDeleted.remove(resourceName);
+ break;
+
+ default:
+ }
+
+ return result;
+ }
+
+ /**
+ * Remove some elements.
+ *
+ * @param type resource operation type
+ * @param resourceNames target resources
+ * @return whether the operation was successful or not
+ */
+ public boolean removeAll(final ResourceOperation type, final Set<String> resourceNames) {
+ Set<String> set;
+ switch (type) {
+ case CREATE:
+ set = toBeCreated;
+ break;
+
+ case UPDATE:
+ set = toBeUpdated;
+ break;
+
+ case DELETE:
+ default:
+ set = toBeDeleted;
+ break;
+ }
+
+ return set.removeAll(resourceNames);
+ }
+
+ /**
+ * Removes only the resource names in the underlying resource name sets that are contained in the specified
+ * collection.
+ *
+ * @param resourceNames collection containing resource names to be retained in the underlying resource name sets
+ * @return <tt>true</tt> if the underlying resource name sets changed as a result of the call
+ * @see Collection#removeAll(java.util.Collection)
+ */
+ public boolean removeAll(final Collection<String> resourceNames) {
+ return toBeCreated.removeAll(resourceNames)
+ | toBeUpdated.removeAll(resourceNames)
+ | toBeDeleted.removeAll(resourceNames);
+ }
+
+ /**
+ * Retains only the resource names in the underlying resource name sets that are contained in the specified
+ * collection.
+ *
+ * @param resourceNames collection containing resource names to be retained in the underlying resource name sets
+ * @return <tt>true</tt> if the underlying resource name sets changed as a result of the call
+ * @see Collection#retainAll(java.util.Collection)
+ */
+ public boolean retainAll(final Collection<String> resourceNames) {
+ return toBeCreated.retainAll(resourceNames)
+ | toBeUpdated.retainAll(resourceNames)
+ | toBeDeleted.retainAll(resourceNames);
+ }
+
+ public boolean contains(final ResourceOperation type, final String resourceName) {
+ boolean result = false;
+
+ switch (type) {
+ case CREATE:
+ result = toBeCreated.contains(resourceName);
+ break;
+
+ case UPDATE:
+ result = toBeUpdated.contains(resourceName);
+ break;
+
+ case DELETE:
+ result = toBeDeleted.contains(resourceName);
+ break;
+
+ default:
+ }
+
+ return result;
+ }
+
+ /**
+ * Get resources for a given resource operation type.
+ *
+ * @param type resource operation type
+ * @return resource matching the given type
+ */
+ public final Set<String> get(final ResourceOperation type) {
+ Set<String> result = Collections.<String>emptySet();
+
+ switch (type) {
+ case CREATE:
+ result = toBeCreated;
+ break;
+
+ case UPDATE:
+ result = toBeUpdated;
+ break;
+
+ case DELETE:
+ result = toBeDeleted;
+ break;
+
+ default:
+ }
+
+ return result;
+ }
+
+ /**
+ * Set resources for a given resource operation type.
+ *
+ * @param type resource operation type
+ * @param resourceNames to be set
+ */
+ public final void set(final ResourceOperation type, final Set<String> resourceNames) {
+
+ switch (type) {
+ case CREATE:
+ toBeCreated.clear();
+ toBeCreated.addAll(resourceNames);
+ break;
+
+ case UPDATE:
+ toBeUpdated.clear();
+ toBeUpdated.addAll(resourceNames);
+ break;
+
+ case DELETE:
+ toBeDeleted.clear();
+ toBeDeleted.addAll(resourceNames);
+ break;
+
+ default:
+ }
+ }
+
+ /**
+ * Merge another resource operation instance into this instance.
+ *
+ * @param propByRes to be merged
+ */
+ public final void merge(final PropagationByResource propByRes) {
+ if (propByRes != null) {
+ toBeCreated.addAll(propByRes.get(ResourceOperation.CREATE));
+ toBeUpdated.addAll(propByRes.get(ResourceOperation.UPDATE));
+ toBeDeleted.addAll(propByRes.get(ResourceOperation.DELETE));
+ oldAccountIds.putAll(propByRes.getOldAccountIds());
+ }
+ }
+
+ /**
+ * Removes all of the operations.
+ */
+ public void clear() {
+ toBeCreated.clear();
+ toBeUpdated.clear();
+ toBeDeleted.clear();
+ }
+
+ /**
+ * Whether no operations are present.
+ *
+ * @return true if no operations (create / update / delete) and no old account ids are present
+ */
+ public final boolean isEmpty() {
+ return toBeCreated.isEmpty() && toBeUpdated.isEmpty() && toBeDeleted.isEmpty() && oldAccountIds.isEmpty();
+ }
+
+ /**
+ * Fetch all old account ids.
+ *
+ * @return old account ids; can be empty
+ */
+ public Map<String, String> getOldAccountIds() {
+ return oldAccountIds;
+ }
+
+ /**
+ * Fetch old account id for given resource name.
+ *
+ * @param resourceName resource name
+ * @return old account id; can be null
+ */
+ public String getOldAccountId(final String resourceName) {
+ return oldAccountIds.get(resourceName);
+ }
+
+ /**
+ * Add old account id for a given resource name.
+ *
+ * @param resourceName resourceName resource name
+ * @param oldAccountId old account id
+ */
+ public void addOldAccountId(final String resourceName, final String oldAccountId) {
+ if (resourceName != null && oldAccountId != null) {
+ oldAccountIds.put(resourceName, oldAccountId);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "To be Created: " + toBeCreated + ";\n"
+ + "To be Updated: " + toBeUpdated + ";\n"
+ + "To be Deleted: " + toBeDeleted + ";\n"
+ + "Old account Ids: " + oldAccountIds;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationException.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationException.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationException.java
new file mode 100644
index 0000000..ff25634
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationException.java
@@ -0,0 +1,51 @@
+/*
+ * 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.provisioning.api.propagation;
+
+/**
+ * Bear stacktrace received during propagation towards a certain resource.
+ */
+public class PropagationException extends RuntimeException {
+
+ private static final long serialVersionUID = -4828426289616526116L;
+
+ /**
+ * The resource involved in this exception.
+ */
+ private final String resourceName;
+
+ /**
+ * Create a new instance based on resource name and original stacktrace received during propagation.
+ *
+ * @param resourceName name of resource involved in this exception
+ * @param stackTrace original stacktrace
+ */
+ public PropagationException(final String resourceName, final String stackTrace) {
+ super("Exception during provision on resource " + resourceName + "\n" + stackTrace);
+
+ this.resourceName = resourceName;
+ }
+
+ /**
+ * @return name of resource involved in this exception
+ */
+ public String getResourceName() {
+ return resourceName;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationManager.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationManager.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationManager.java
new file mode 100644
index 0000000..d2060c9
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationManager.java
@@ -0,0 +1,248 @@
+/*
+ * 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.provisioning.api.propagation;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.mod.MembershipMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.persistence.api.entity.Subject;
+import org.apache.syncope.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.provisioning.api.WorkflowResult;
+
+public interface PropagationManager {
+
+ /**
+ * Create the role on every associated resource.
+ *
+ * @param wfResult user to be propagated (and info associated), as per result from workflow
+ * @param vAttrs virtual attributes to be set
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getRoleCreateTaskIds(WorkflowResult<Long> wfResult, List<AttrTO> vAttrs);
+
+ /**
+ * Create the role on every associated resource.
+ *
+ * @param wfResult role to be propagated (and info associated), as per result from workflow
+ * @param vAttrs virtual attributes to be set
+ * @param noPropResourceNames external resources performing not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getRoleCreateTaskIds(
+ WorkflowResult<Long> wfResult, Collection<AttrTO> vAttrs, Collection<String> noPropResourceNames);
+
+ /**
+ * Create the role on every associated resource.
+ *
+ * @param key role id
+ * @param vAttrs virtual attributes to be set
+ * @param propByRes operation to be performed per resource
+ * @param noPropResourceNames external resources performing not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getRoleCreateTaskIds(Long key, Collection<AttrTO> vAttrs, PropagationByResource propByRes,
+ Collection<String> noPropResourceNames);
+
+ /**
+ * Perform delete on each resource associated to the role. It is possible to ask for a mandatory provisioning for
+ * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
+ * the creation fails onto a mandatory resource.
+ *
+ * @param roleId to be deleted
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getRoleDeleteTaskIds(Long roleId);
+
+ /**
+ * Perform delete on each resource associated to the role. It is possible to ask for a mandatory provisioning for
+ * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
+ * the creation fails onto a mandatory resource.
+ *
+ * @param roleId to be deleted
+ * @param noPropResourceName name of external resource not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getRoleDeleteTaskIds(Long roleId, String noPropResourceName);
+
+ /**
+ * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
+ * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
+ * the creation fails onto a mandatory resource.
+ *
+ * @param roleId to be deleted
+ * @param noPropResourceNames name of external resources not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getRoleDeleteTaskIds(Long roleId, Collection<String> noPropResourceNames);
+
+ /**
+ * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
+ * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
+ * the creation fails onto a mandatory resource.
+ *
+ * @param roleId to be deleted
+ * @param noPropResourceNames name of external resources not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getRoleDeleteTaskIds(
+ Long roleId, Set<String> resourceNames, Collection<String> noPropResourceNames);
+
+ /**
+ * Performs update on each resource associated to the role.
+ *
+ * @param wfResult role to be propagated (and info associated), as per result from workflow
+ * @param vAttrsToBeRemoved virtual attributes to be removed
+ * @param vAttrsToBeUpdated virtual attributes to be added
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getRoleUpdateTaskIds(WorkflowResult<Long> wfResult, Set<String> vAttrsToBeRemoved,
+ Set<AttrMod> vAttrsToBeUpdated);
+
+ /**
+ * Performs update on each resource associated to the role.
+ *
+ * @param wfResult role to be propagated (and info associated), as per result from workflow
+ * @param vAttrsToBeRemoved virtual attributes to be removed
+ * @param vAttrsToBeUpdated virtual attributes to be added
+ * @param noPropResourceNames external resource names not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getRoleUpdateTaskIds(WorkflowResult<Long> wfResult, Set<String> vAttrsToBeRemoved,
+ Set<AttrMod> vAttrsToBeUpdated, Set<String> noPropResourceNames);
+
+ List<PropagationTask> getUpdateTaskIds(Subject<?, ?, ?> subject, String password, boolean changePwd,
+ Boolean enable, Set<String> vAttrsToBeRemoved, Set<AttrMod> vAttrsToBeUpdated,
+ PropagationByResource propByRes, Collection<String> noPropResourceNames,
+ Set<MembershipMod> membershipsToAdd);
+
+ /**
+ * Create the user on every associated resource.
+ *
+ * @param wfResult user to be propagated (and info associated), as per result from workflow
+ * @param password to be set
+ * @param vAttrs virtual attributes to be set
+ * @param membershipTOs user memberships
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getUserCreateTaskIds(WorkflowResult<Map.Entry<Long, Boolean>> wfResult,
+ String password, List<AttrTO> vAttrs, List<MembershipTO> membershipTOs);
+
+ /**
+ * Create the user on every associated resource.
+ *
+ * @param wfResult user to be propagated (and info associated), as per result from workflow
+ * @param password to be set
+ * @param vAttrs virtual attributes to be set
+ * @param noPropResourceNames external resources not to be considered for propagation
+ * @param membershipTOs user memberships
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getUserCreateTaskIds(WorkflowResult<Map.Entry<Long, Boolean>> wfResult,
+ String password, Collection<AttrTO> vAttrs, Set<String> noPropResourceNames,
+ List<MembershipTO> membershipTOs);
+
+ List<PropagationTask> getUserCreateTaskIds(Long id, Boolean enabled,
+ PropagationByResource propByRes, String password, Collection<AttrTO> vAttrs,
+ Collection<MembershipTO> membershipTOs, Collection<String> noPropResourceNames);
+
+ /**
+ * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
+ * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
+ * the creation fails onto a mandatory resource.
+ *
+ * @param userKey to be deleted
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getUserDeleteTaskIds(Long userKey);
+
+ /**
+ * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
+ * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
+ * the creation fails onto a mandatory resource.
+ *
+ * @param userKey to be deleted
+ * @param noPropResourceName name of external resource not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getUserDeleteTaskIds(Long userKey, String noPropResourceName);
+
+ /**
+ * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
+ * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
+ * the creation fails onto a mandatory resource.
+ *
+ * @param userKey to be deleted
+ * @param noPropResourceNames name of external resources not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getUserDeleteTaskIds(Long userKey, Collection<String> noPropResourceNames);
+
+ /**
+ * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
+ * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
+ * the creation fails onto a mandatory resource.
+ *
+ * @param userKey to be deleted
+ * @param noPropResourceNames name of external resources not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getUserDeleteTaskIds(
+ Long userKey, Set<String> resourceNames, Collection<String> noPropResourceNames);
+
+ /**
+ * Perform delete on each resource associated to the user. It is possible to ask for a mandatory provisioning for
+ * some resources specifying a set of resource names. Exceptions won't be ignored and the process will be stopped if
+ * the creation fails onto a mandatory resource.
+ *
+ * @param wfResult user to be propagated (and info associated), as per result from workflow
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getUserDeleteTaskIds(WorkflowResult<Long> wfResult);
+
+ /**
+ * Performs update on each resource associated to the user excluding the specified into 'resourceNames' parameter.
+ *
+ * @param user to be propagated
+ * @param enable whether user must be enabled or not
+ * @param noPropResourceNames external resource names not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getUserUpdateTaskIds(User user, Boolean enable, Set<String> noPropResourceNames);
+
+ /**
+ * Performs update on each resource associated to the user.
+ *
+ * @param wfResult user to be propagated (and info associated), as per result from workflow
+ * @param changePwd whether password should be included for propagation attributes or not
+ * @param noPropResourceNames external resources not to be considered for propagation
+ * @return list of propagation tasks
+ */
+ List<PropagationTask> getUserUpdateTaskIds(WorkflowResult<Map.Entry<UserMod, Boolean>> wfResult,
+ boolean changePwd, Collection<String> noPropResourceNames);
+
+ List<PropagationTask> getUserUpdateTaskIds(WorkflowResult<Map.Entry<UserMod, Boolean>> wfResult);
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationReporter.java
----------------------------------------------------------------------
diff --git a/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationReporter.java b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationReporter.java
new file mode 100644
index 0000000..b4b714b
--- /dev/null
+++ b/syncope620/server/provisioning-api/src/main/java/org/apache/syncope/provisioning/api/propagation/PropagationReporter.java
@@ -0,0 +1,58 @@
+/*
+ * 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.provisioning.api.propagation;
+
+import java.util.List;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
+import org.apache.syncope.persistence.api.entity.task.PropagationTask;
+import org.identityconnectors.framework.common.objects.ConnectorObject;
+
+/**
+ * Report propagation status after executions.
+ */
+public interface PropagationReporter {
+
+ /**
+ * Report propagation status after executions in case of success or non-blocking failure
+ * (e.g. on secondary resources).
+ *
+ * @param resourceName resource name.
+ * @param execStatus propagation execution status.
+ * @param failureReason propagation execution failure message.
+ * @param beforeObj retrieved connector object before operation execution.
+ * @param afterObj retrieved connector object after operation execution.
+ */
+ void onSuccessOrSecondaryResourceFailures(String resourceName, PropagationTaskExecStatus execStatus,
+ String failureReason, ConnectorObject beforeObj, ConnectorObject afterObj);
+
+ /**
+ * Report propagation status after executions in case blocking failure (e.g. on primary resources).
+ *
+ * @param tasks propagation tasks performed before failure
+ */
+ void onPrimaryResourceFailure(List<PropagationTask> tasks);
+
+ /**
+ * Returns the list of propagation statuses.
+ *
+ * @return the list of propagation statuses
+ */
+ List<PropagationStatus> getStatuses();
+}
[06/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/TaskDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/TaskDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/TaskDataBinder.java
new file mode 100644
index 0000000..204207b
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/TaskDataBinder.java
@@ -0,0 +1,338 @@
+/*
+ * 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.server.logic.data;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractProvisioningTaskTO;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.to.SyncTaskTO;
+import org.apache.syncope.common.lib.to.TaskExecTO;
+import org.apache.syncope.common.lib.to.UserTO;
+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.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.TaskExecDAO;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.task.NotificationTask;
+import org.apache.syncope.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.persistence.api.entity.task.ProvisioningTask;
+import org.apache.syncope.persistence.api.entity.task.PushTask;
+import org.apache.syncope.persistence.api.entity.task.SchedTask;
+import org.apache.syncope.persistence.api.entity.task.SyncTask;
+import org.apache.syncope.persistence.api.entity.task.Task;
+import org.apache.syncope.persistence.api.entity.task.TaskExec;
+import org.apache.syncope.persistence.api.entity.task.TaskUtil;
+import org.apache.syncope.server.logic.init.JobInstanceLoader;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.apache.syncope.server.utils.jexl.JexlUtil;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.TriggerKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+import org.springframework.stereotype.Component;
+
+@Component
+public class TaskDataBinder {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(TaskDataBinder.class);
+
+ private static final String[] IGNORE_TASK_PROPERTIES = {
+ "executions", "resource", "matchingRule", "unmatchingRule" };
+
+ private static final String[] IGNORE_TASK_EXECUTION_PROPERTIES = { "key", "task" };
+
+ @Autowired
+ private ExternalResourceDAO resourceDAO;
+
+ @Autowired
+ private TaskExecDAO taskExecDAO;
+
+ @Autowired
+ private SchedulerFactoryBean scheduler;
+
+ private void checkJexl(final AbstractAttributableTO attributableTO, final SyncopeClientException sce) {
+ for (AttrTO attrTO : attributableTO.getPlainAttrs()) {
+ if (!attrTO.getValues().isEmpty() && !JexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
+ sce.getElements().add("Invalid JEXL: " + attrTO.getValues().get(0));
+ }
+ }
+
+ for (AttrTO attrTO : attributableTO.getVirAttrs()) {
+ if (!attrTO.getValues().isEmpty() && !JexlUtil.isExpressionValid(attrTO.getValues().get(0))) {
+ sce.getElements().add("Invalid JEXL: " + attrTO.getValues().get(0));
+ }
+ }
+ }
+
+ private void fill(final ProvisioningTask task, final AbstractProvisioningTaskTO taskTO) {
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.InvalidSyncTask);
+
+ if (task instanceof PushTask && taskTO instanceof PushTaskTO) {
+ final PushTask pushTask = (PushTask) task;
+ final PushTaskTO pushTaskTO = (PushTaskTO) taskTO;
+
+ pushTask.setUserFilter(pushTaskTO.getUserFilter());
+ pushTask.setRoleFilter(pushTaskTO.getRoleFilter());
+
+ pushTask.setMatchingRule(pushTaskTO.getMatchingRule() == null
+ ? MatchingRule.LINK : pushTaskTO.getMatchingRule());
+
+ pushTask.setUnmatchingRule(pushTaskTO.getUnmatchingRule() == null
+ ? UnmatchingRule.ASSIGN : pushTaskTO.getUnmatchingRule());
+
+ } else if (task instanceof SyncTask && taskTO instanceof SyncTaskTO) {
+ final SyncTask syncTask = (SyncTask) task;
+ final SyncTaskTO syncTaskTO = (SyncTaskTO) taskTO;
+
+ syncTask.setMatchingRule(syncTaskTO.getMatchingRule() == null
+ ? MatchingRule.UPDATE : syncTaskTO.getMatchingRule());
+
+ syncTask.setUnmatchingRule(syncTaskTO.getUnmatchingRule() == null
+ ? UnmatchingRule.PROVISION : syncTaskTO.getUnmatchingRule());
+
+ // 1. validate JEXL expressions in user and role templates
+ if (syncTaskTO.getUserTemplate() != null) {
+ UserTO template = syncTaskTO.getUserTemplate();
+
+ if (StringUtils.isNotBlank(template.getUsername())
+ && !JexlUtil.isExpressionValid(template.getUsername())) {
+
+ sce.getElements().add("Invalid JEXL: " + template.getUsername());
+ }
+ if (StringUtils.isNotBlank(template.getPassword())
+ && !JexlUtil.isExpressionValid(template.getPassword())) {
+
+ sce.getElements().add("Invalid JEXL: " + template.getPassword());
+ }
+
+ checkJexl(template, sce);
+
+ for (MembershipTO memb : template.getMemberships()) {
+ checkJexl(memb, sce);
+ }
+ }
+ if (syncTaskTO.getRoleTemplate() != null) {
+ RoleTO template = syncTaskTO.getRoleTemplate();
+
+ if (StringUtils.isNotBlank(template.getName()) && !JexlUtil.isExpressionValid(template.getName())) {
+ sce.getElements().add("Invalid JEXL: " + template.getName());
+ }
+
+ checkJexl(template, sce);
+ }
+ if (!sce.isEmpty()) {
+ throw sce;
+ }
+
+ // 2. all JEXL expressions are valid: accept user and role templates
+ syncTask.setUserTemplate(syncTaskTO.getUserTemplate());
+ syncTask.setRoleTemplate(syncTaskTO.getRoleTemplate());
+
+ syncTask.setFullReconciliation(syncTaskTO.isFullReconciliation());
+ }
+
+ // 3. fill the remaining fields
+ task.setPerformCreate(taskTO.isPerformCreate());
+ task.setPerformUpdate(taskTO.isPerformUpdate());
+ task.setPerformDelete(taskTO.isPerformDelete());
+ task.setSyncStatus(taskTO.isSyncStatus());
+ task.getActionsClassNames().clear();
+ task.getActionsClassNames().addAll(taskTO.getActionsClassNames());
+ }
+
+ public SchedTask createSchedTask(final SchedTaskTO taskTO, final TaskUtil taskUtil) {
+ final Class<? extends AbstractTaskTO> taskTOClass = taskUtil.taskTOClass();
+
+ if (taskTOClass == null || !taskTOClass.equals(taskTO.getClass())) {
+ throw new ClassCastException(
+ String.format("taskUtil is type %s but task is not: %s", taskTOClass, taskTO.getClass()));
+ }
+
+ SchedTask task = taskUtil.newTask();
+ task.setCronExpression(taskTO.getCronExpression());
+ task.setName(taskTO.getName());
+ task.setDescription(taskTO.getDescription());
+
+ if (taskUtil.getType() == TaskType.SCHEDULED) {
+ task.setJobClassName(taskTO.getJobClassName());
+ } else if (taskTO instanceof AbstractProvisioningTaskTO) {
+ final AbstractProvisioningTaskTO provisioningTaskTO = (AbstractProvisioningTaskTO) taskTO;
+
+ ExternalResource resource = resourceDAO.find(provisioningTaskTO.getResource());
+ if (resource == null) {
+ throw new NotFoundException("Resource " + provisioningTaskTO.getResource());
+ }
+ ((ProvisioningTask) task).setResource(resource);
+
+ fill((ProvisioningTask) task, provisioningTaskTO);
+ }
+
+ return task;
+ }
+
+ public void updateSchedTask(final SchedTask task, final SchedTaskTO taskTO, final TaskUtil taskUtil) {
+ Class<? extends Task> taskClass = taskUtil.taskClass();
+ Class<? extends AbstractTaskTO> taskTOClass = taskUtil.taskTOClass();
+
+ if (taskClass == null || !taskClass.equals(task.getClass())) {
+ throw new ClassCastException(
+ String.format("taskUtil is type %s but task is not: %s", taskClass, task.getClass()));
+ }
+
+ if (taskTOClass == null || !taskTOClass.equals(taskTO.getClass())) {
+ throw new ClassCastException(
+ String.format("taskUtil is type %s but task is not: %s", taskTOClass, taskTO.getClass()));
+ }
+
+ task.setCronExpression(taskTO.getCronExpression());
+ if (StringUtils.isNotBlank(taskTO.getName())) {
+ task.setName(taskTO.getName());
+ }
+ if (StringUtils.isNotBlank(taskTO.getDescription())) {
+ task.setDescription(taskTO.getDescription());
+ }
+
+ if (task instanceof ProvisioningTask) {
+ fill((ProvisioningTask) task, (AbstractProvisioningTaskTO) taskTO);
+ }
+ }
+
+ public TaskExecTO getTaskExecTO(final TaskExec execution) {
+ TaskExecTO executionTO = new TaskExecTO();
+ BeanUtils.copyProperties(execution, executionTO, IGNORE_TASK_EXECUTION_PROPERTIES);
+
+ if (execution.getKey() != null) {
+ executionTO.setKey(execution.getKey());
+ }
+
+ if (execution.getTask() != null && execution.getTask().getKey() != null) {
+ executionTO.setTask(execution.getTask().getKey());
+ }
+
+ return executionTO;
+ }
+
+ private void setExecTime(final SchedTaskTO taskTO, final Task task) {
+ String triggerName = JobInstanceLoader.getTriggerName(JobInstanceLoader.getJobName(task));
+
+ Trigger trigger = null;
+ try {
+ trigger = scheduler.getScheduler().getTrigger(new TriggerKey(triggerName, Scheduler.DEFAULT_GROUP));
+ } catch (SchedulerException e) {
+ LOG.warn("While trying to get to " + triggerName, e);
+ }
+
+ if (trigger != null) {
+ taskTO.setLastExec(trigger.getPreviousFireTime());
+ taskTO.setNextExec(trigger.getNextFireTime());
+ }
+ }
+
+ public <T extends AbstractTaskTO> T getTaskTO(final Task task, final TaskUtil taskUtil) {
+ T taskTO = taskUtil.newTaskTO();
+ BeanUtils.copyProperties(task, taskTO, IGNORE_TASK_PROPERTIES);
+
+ TaskExec latestExec = taskExecDAO.findLatestStarted(task);
+ taskTO.setLatestExecStatus(latestExec == null ? "" : latestExec.getStatus());
+ taskTO.setStartDate(latestExec == null ? null : latestExec.getStartDate());
+ taskTO.setEndDate(latestExec == null ? null : latestExec.getEndDate());
+
+ for (TaskExec execution : task.getExecs()) {
+ taskTO.getExecutions().add(getTaskExecTO(execution));
+ }
+
+ switch (taskUtil.getType()) {
+ case PROPAGATION:
+ if (!(task instanceof PropagationTask)) {
+ throw new ClassCastException("taskUtil is type Propagation but task is not PropagationTask: "
+ + task.getClass().getName());
+ }
+ ((PropagationTaskTO) taskTO).setResource(((PropagationTask) task).getResource().getKey());
+ break;
+
+ case SCHEDULED:
+ if (!(task instanceof SchedTask)) {
+ throw new ClassCastException("taskUtil is type Sched but task is not SchedTask: "
+ + task.getClass().getName());
+ }
+ setExecTime((SchedTaskTO) taskTO, task);
+ ((SchedTaskTO) taskTO).setName(((SchedTask) task).getName());
+ ((SchedTaskTO) taskTO).setDescription(((SchedTask) task).getDescription());
+ break;
+
+ case SYNCHRONIZATION:
+ if (!(task instanceof SyncTask)) {
+ throw new ClassCastException("taskUtil is type Sync but task is not SyncTask: "
+ + task.getClass().getName());
+ }
+ setExecTime((SchedTaskTO) taskTO, task);
+ ((SyncTaskTO) taskTO).setName(((SyncTask) task).getName());
+ ((SyncTaskTO) taskTO).setDescription(((SyncTask) task).getDescription());
+ ((SyncTaskTO) taskTO).setResource(((SyncTask) task).getResource().getKey());
+ ((SyncTaskTO) taskTO).setMatchingRule(((SyncTask) task).getMatchingRule() == null
+ ? MatchingRule.UPDATE : ((SyncTask) task).getMatchingRule());
+ ((SyncTaskTO) taskTO).setUnmatchingRule(((SyncTask) task).getUnmatchingRule() == null
+ ? UnmatchingRule.PROVISION : ((SyncTask) task).getUnmatchingRule());
+ break;
+
+ case PUSH:
+ if (!(task instanceof PushTask)) {
+ throw new ClassCastException("taskUtil is type Push but task is not PushTask: "
+ + task.getClass().getName());
+ }
+ setExecTime((SchedTaskTO) taskTO, task);
+ ((PushTaskTO) taskTO).setName(((PushTask) task).getName());
+ ((PushTaskTO) taskTO).setDescription(((PushTask) task).getDescription());
+ ((PushTaskTO) taskTO).setResource(((PushTask) task).getResource().getKey());
+ ((PushTaskTO) taskTO).setMatchingRule(((PushTask) task).getMatchingRule() == null
+ ? MatchingRule.LINK : ((PushTask) task).getMatchingRule());
+ ((PushTaskTO) taskTO).setUnmatchingRule(((PushTask) task).getUnmatchingRule() == null
+ ? UnmatchingRule.ASSIGN : ((PushTask) task).getUnmatchingRule());
+ break;
+
+ case NOTIFICATION:
+ if (((NotificationTask) task).isExecuted() && StringUtils.isBlank(taskTO.getLatestExecStatus())) {
+ taskTO.setLatestExecStatus("[EXECUTED]");
+ }
+ break;
+
+ default:
+ }
+
+ return taskTO;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/UserDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/UserDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/UserDataBinder.java
new file mode 100644
index 0000000..861452c
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/UserDataBinder.java
@@ -0,0 +1,479 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Resource;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.mod.MembershipMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.CipherAlgorithm;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.persistence.api.dao.ConfDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.SecurityQuestionDAO;
+import org.apache.syncope.persistence.api.entity.DerAttr;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.MappingItem;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+import org.apache.syncope.persistence.api.entity.VirAttr;
+import org.apache.syncope.persistence.api.entity.membership.MDerAttr;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttr;
+import org.apache.syncope.persistence.api.entity.membership.MVirAttr;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.user.SecurityQuestion;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.provisioning.api.propagation.PropagationByResource;
+import org.apache.syncope.server.security.AuthContextUtil;
+import org.apache.syncope.server.security.Encryptor;
+import org.apache.syncope.server.spring.BeanUtils;
+import org.apache.syncope.server.utils.ConnObjectUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+@Transactional(rollbackFor = { Throwable.class })
+public class UserDataBinder extends AbstractAttributableDataBinder {
+
+ private static final String[] IGNORE_USER_PROPERTIES = {
+ "memberships", "plainAttrs", "derAttrs", "virAttrs", "resources", "securityQuestion", "securityAnswer"
+ };
+
+ @Autowired
+ private ConfDAO confDAO;
+
+ @Autowired
+ private ConnObjectUtil connObjectUtil;
+
+ @Autowired
+ private SecurityQuestionDAO securityQuestionDAO;
+
+ @Resource(name = "adminUser")
+ private String adminUser;
+
+ @Resource(name = "anonymousUser")
+ private String anonymousUser;
+
+ private final Encryptor encryptor = Encryptor.getInstance();
+
+ @Transactional(readOnly = true)
+ public Membership getMembershipFromId(final Long membershipId) {
+ if (membershipId == null) {
+ throw new NotFoundException("Null membership id");
+ }
+
+ Membership membership = membershipDAO.find(membershipId);
+ if (membership == null) {
+ throw new NotFoundException("Membership " + membershipId);
+ }
+
+ return membership;
+ }
+
+ @Transactional(readOnly = true)
+ public Set<String> getResourceNamesForUser(final Long key) {
+ return userDAO.authFecthUser(key).getResourceNames();
+ }
+
+ @Transactional(readOnly = true)
+ public UserTO getAuthenticatedUserTO() {
+ final UserTO authUserTO;
+
+ final String authUsername = AuthContextUtil.getAuthenticatedUsername();
+ if (anonymousUser.equals(authUsername)) {
+ authUserTO = new UserTO();
+ authUserTO.setKey(-2);
+ authUserTO.setUsername(anonymousUser);
+ } else if (adminUser.equals(authUsername)) {
+ authUserTO = new UserTO();
+ authUserTO.setKey(-1);
+ authUserTO.setUsername(adminUser);
+ } else {
+ User authUser = userDAO.find(authUsername);
+ authUserTO = getUserTO(authUser);
+ }
+
+ return authUserTO;
+ }
+
+ @Transactional(readOnly = true)
+ public boolean verifyPassword(final String username, final String password) {
+ return verifyPassword(userDAO.authFecthUser(username), password);
+ }
+
+ @Transactional(readOnly = true)
+ public boolean verifyPassword(final User user, final String password) {
+ return encryptor.verify(password, user.getCipherAlgorithm(), user.getPassword());
+ }
+
+ private void setPassword(final User user, final String password,
+ final SyncopeClientCompositeException scce) {
+
+ try {
+ final String algorithm = confDAO.find(
+ "password.cipher.algorithm", CipherAlgorithm.AES.name()).getValues().get(0).getStringValue();
+ CipherAlgorithm predefined = CipherAlgorithm.valueOf(algorithm);
+ user.setPassword(password, predefined);
+ } catch (IllegalArgumentException e) {
+ final SyncopeClientException invalidCiperAlgorithm =
+ SyncopeClientException.build(ClientExceptionType.NotFound);
+ invalidCiperAlgorithm.getElements().add(e.getMessage());
+ scce.addException(invalidCiperAlgorithm);
+
+ throw scce;
+ }
+ }
+
+ public void create(final User user, final UserTO userTO, final boolean storePassword) {
+ SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+ // memberships
+ Role role;
+ for (MembershipTO membershipTO : userTO.getMemberships()) {
+ role = roleDAO.find(membershipTO.getRoleId());
+
+ if (role == null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Ignoring invalid role " + membershipTO.getRoleName());
+ }
+ } else {
+ Membership membership = null;
+ if (user.getKey() != null) {
+ membership = user.getMembership(role.getKey()) == null
+ ? membershipDAO.find(user, role)
+ : user.getMembership(role.getKey());
+ }
+ if (membership == null) {
+ membership = entityFactory.newEntity(Membership.class);
+ membership.setRole(role);
+ membership.setUser(user);
+
+ user.addMembership(membership);
+ }
+
+ fill(membership, membershipTO, attrUtilFactory.getInstance(AttributableType.MEMBERSHIP), scce);
+ }
+ }
+
+ // attributes, derived attributes, virtual attributes and resources
+ fill(user, userTO, attrUtilFactory.getInstance(AttributableType.USER), scce);
+
+ // set password
+ if (StringUtils.isBlank(userTO.getPassword()) || !storePassword) {
+ LOG.debug("Password was not provided or not required to be stored");
+ } else {
+ setPassword(user, userTO.getPassword(), scce);
+ }
+
+ // set username
+ user.setUsername(userTO.getUsername());
+
+ // security question / answer
+ if (userTO.getSecurityQuestion() != null) {
+ SecurityQuestion securityQuestion = securityQuestionDAO.find(userTO.getSecurityQuestion());
+ if (securityQuestion != null) {
+ user.setSecurityQuestion(securityQuestion);
+ }
+ }
+ user.setSecurityAnswer(userTO.getSecurityAnswer());
+ }
+
+ /**
+ * Update user, given UserMod.
+ *
+ * @param toBeUpdated user to be updated
+ * @param userMod bean containing update request
+ * @return updated user + propagation by resource
+ * @see PropagationByResource
+ */
+ public PropagationByResource update(final User toBeUpdated, final UserMod userMod) {
+ // Re-merge any pending change from workflow tasks
+ User user = userDAO.save(toBeUpdated);
+
+ PropagationByResource propByRes = new PropagationByResource();
+
+ SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
+
+ Set<String> currentResources = user.getResourceNames();
+
+ // password
+ if (StringUtils.isNotBlank(userMod.getPassword())) {
+ setPassword(user, userMod.getPassword(), scce);
+ user.setChangePwdDate(new Date());
+ propByRes.addAll(ResourceOperation.UPDATE, currentResources);
+ }
+
+ // username
+ if (userMod.getUsername() != null && !userMod.getUsername().equals(user.getUsername())) {
+ String oldUsername = user.getUsername();
+
+ user.setUsername(userMod.getUsername());
+ propByRes.addAll(ResourceOperation.UPDATE, currentResources);
+
+ for (ExternalResource resource : user.getResources()) {
+ for (MappingItem mapItem : resource.getUmapping().getItems()) {
+ if (mapItem.isAccountid() && mapItem.getIntMappingType() == IntMappingType.Username) {
+ propByRes.addOldAccountId(resource.getKey(), oldUsername);
+ }
+ }
+ }
+ }
+
+ // security question / answer:
+ // userMod.getSecurityQuestion() is null => remove user security question and answer
+ // userMod.getSecurityQuestion() == 0 => don't change anything
+ // userMod.getSecurityQuestion() > 0 => update user security question and answer
+ if (userMod.getSecurityQuestion() == null) {
+ user.setSecurityQuestion(null);
+ user.setSecurityAnswer(null);
+ } else if (userMod.getSecurityQuestion() > 0) {
+ SecurityQuestion securityQuestion = securityQuestionDAO.find(userMod.getSecurityQuestion());
+ if (securityQuestion != null) {
+ user.setSecurityQuestion(securityQuestion);
+ user.setSecurityAnswer(userMod.getSecurityAnswer());
+ }
+ }
+
+ // attributes, derived attributes, virtual attributes and resources
+ propByRes.merge(fill(user, userMod, attrUtilFactory.getInstance(AttributableType.USER), scce));
+
+ // store the role ids of membership required to be added
+ Set<Long> membershipToBeAddedRoleIds = new HashSet<>();
+ for (MembershipMod membToBeAdded : userMod.getMembershipsToAdd()) {
+ membershipToBeAddedRoleIds.add(membToBeAdded.getRole());
+ }
+
+ final Set<String> toBeDeprovisioned = new HashSet<>();
+ final Set<String> toBeProvisioned = new HashSet<>();
+
+ // memberships to be removed
+ for (Long membershipId : userMod.getMembershipsToRemove()) {
+ LOG.debug("Membership to be removed: {}", membershipId);
+
+ Membership membership = membershipDAO.find(membershipId);
+ if (membership == null) {
+ LOG.debug("Invalid membership id specified to be removed: {}", membershipId);
+ } else {
+ if (!membershipToBeAddedRoleIds.contains(membership.getRole().getKey())) {
+ toBeDeprovisioned.addAll(membership.getRole().getResourceNames());
+ }
+
+ // In order to make the removeMembership() below to work,
+ // we need to be sure to take exactly the same membership
+ // of the user object currently in memory (which has potentially
+ // some modifications compared to the one stored in the DB
+ membership = user.getMembership(membership.getRole().getKey());
+ if (membershipToBeAddedRoleIds.contains(membership.getRole().getKey())) {
+ Set<Long> attributeIds = new HashSet<>(membership.getPlainAttrs().size());
+ for (PlainAttr attribute : membership.getPlainAttrs()) {
+ attributeIds.add(attribute.getKey());
+ }
+ for (Long attributeId : attributeIds) {
+ plainAttrDAO.delete(attributeId, MPlainAttr.class);
+ }
+ attributeIds.clear();
+
+ // remove derived attributes
+ for (DerAttr derAttr : membership.getDerAttrs()) {
+ attributeIds.add(derAttr.getKey());
+ }
+ for (Long derAttrId : attributeIds) {
+ derAttrDAO.delete(derAttrId, MDerAttr.class);
+ }
+ attributeIds.clear();
+
+ // remove virtual attributes
+ for (VirAttr virAttr : membership.getVirAttrs()) {
+ attributeIds.add(virAttr.getKey());
+ }
+ for (Long virAttrId : attributeIds) {
+ virAttrDAO.delete(virAttrId, MVirAttr.class);
+ }
+ attributeIds.clear();
+ } else {
+ user.removeMembership(membership);
+
+ membershipDAO.delete(membershipId);
+ }
+ }
+ }
+
+ // memberships to be added
+ for (MembershipMod membershipMod : userMod.getMembershipsToAdd()) {
+ LOG.debug("Membership to be added: role({})", membershipMod.getRole());
+
+ Role role = roleDAO.find(membershipMod.getRole());
+ if (role == null) {
+ LOG.debug("Ignoring invalid role {}", membershipMod.getRole());
+ } else {
+ Membership membership = user.getMembership(role.getKey());
+ if (membership == null) {
+ membership = entityFactory.newEntity(Membership.class);
+ membership.setRole(role);
+ membership.setUser(user);
+
+ user.addMembership(membership);
+
+ toBeProvisioned.addAll(role.getResourceNames());
+ }
+
+ propByRes.merge(fill(membership, membershipMod,
+ attrUtilFactory.getInstance(AttributableType.MEMBERSHIP), scce));
+ }
+ }
+
+ propByRes.addAll(ResourceOperation.DELETE, toBeDeprovisioned);
+ propByRes.addAll(ResourceOperation.UPDATE, toBeProvisioned);
+
+ /**
+ * In case of new memberships all the current resources have to be updated in order to propagate new role and
+ * membership attribute values.
+ */
+ if (!toBeDeprovisioned.isEmpty() || !toBeProvisioned.isEmpty()) {
+ currentResources.removeAll(toBeDeprovisioned);
+ propByRes.addAll(ResourceOperation.UPDATE, currentResources);
+ }
+
+ return propByRes;
+ }
+
+ @Transactional(readOnly = true)
+ public UserTO getUserTO(final User user) {
+ UserTO userTO = new UserTO();
+
+ BeanUtils.copyProperties(user, userTO, IGNORE_USER_PROPERTIES);
+
+ if (user.getSecurityQuestion() != null) {
+ userTO.setSecurityQuestion(user.getSecurityQuestion().getKey());
+ }
+
+ connObjectUtil.retrieveVirAttrValues(user, attrUtilFactory.getInstance(AttributableType.USER));
+ fillTO(userTO, user.getPlainAttrs(), user.getDerAttrs(), user.getVirAttrs(), user.getResources());
+
+ MembershipTO membershipTO;
+ for (Membership membership : user.getMemberships()) {
+ membershipTO = new MembershipTO();
+
+ // set sys info
+ membershipTO.setCreator(membership.getCreator());
+ membershipTO.setCreationDate(membership.getCreationDate());
+ membershipTO.setLastModifier(membership.getLastModifier());
+ membershipTO.setLastChangeDate(membership.getLastChangeDate());
+
+ membershipTO.setKey(membership.getKey());
+ membershipTO.setRoleId(membership.getRole().getKey());
+ membershipTO.setRoleName(membership.getRole().getName());
+
+ // SYNCOPE-458 retrieve also membership virtual attributes
+ connObjectUtil.retrieveVirAttrValues(membership, attrUtilFactory.getInstance(AttributableType.MEMBERSHIP));
+
+ fillTO(membershipTO,
+ membership.getPlainAttrs(), membership.getDerAttrs(), membership.getVirAttrs(),
+ Collections.<ExternalResource>emptyList());
+
+ userTO.getMemberships().add(membershipTO);
+ }
+
+ return userTO;
+ }
+
+ @Transactional(readOnly = true)
+ public UserTO getUserTO(final String username) {
+ return getUserTO(userDAO.authFecthUser(username));
+ }
+
+ @Transactional(readOnly = true)
+ public UserTO getUserTO(final Long key) {
+ return getUserTO(userDAO.authFecthUser(key));
+ }
+
+ /**
+ * SYNCOPE-459: build virtual attribute changes in case no other changes were made.
+ *
+ * @param key user id
+ * @param vAttrsToBeRemoved virtual attributes to be removed.
+ * @param vAttrsToBeUpdated virtual attributes to be updated.
+ * @return operations to be performed on external resources for virtual attributes changes
+ */
+ public PropagationByResource fillVirtual(
+ final Long key, final Set<String> vAttrsToBeRemoved, final Set<AttrMod> vAttrsToBeUpdated) {
+
+ return fillVirtual(
+ userDAO.authFecthUser(key),
+ vAttrsToBeRemoved,
+ vAttrsToBeUpdated,
+ attrUtilFactory.getInstance(AttributableType.USER));
+ }
+
+ /**
+ * SYNCOPE-501: build membership virtual attribute changes in case no other changes were made.
+ *
+ * @param key user id
+ * @param roleId role id
+ * @param membershipId membership id
+ * @param vAttrsToBeRemoved virtual attributes to be removed.
+ * @param vAttrsToBeUpdated virtual attributes to be updated.
+ * @param isRemoval flag to check if fill is on removed or added membership
+ * @return operations to be performed on external resources for membership virtual attributes changes
+ */
+ public PropagationByResource fillMembershipVirtual(
+ final Long key, final Long roleId, final Long membershipId, final Set<String> vAttrsToBeRemoved,
+ final Set<AttrMod> vAttrsToBeUpdated, final boolean isRemoval) {
+
+ final Membership membership = membershipId == null
+ ? userDAO.authFecthUser(key).getMembership(roleId)
+ : getMembershipFromId(membershipId);
+
+ return membership == null ? new PropagationByResource() : isRemoval
+ ? fillVirtual(
+ membership,
+ membership.getVirAttrs() == null
+ ? Collections.<String>emptySet()
+ : getAttributeNames(membership.getVirAttrs()),
+ vAttrsToBeUpdated,
+ attrUtilFactory.getInstance(AttributableType.MEMBERSHIP))
+ : fillVirtual(
+ membership,
+ vAttrsToBeRemoved,
+ vAttrsToBeUpdated,
+ attrUtilFactory.getInstance(AttributableType.MEMBERSHIP));
+ }
+
+ private Set<String> getAttributeNames(final List<? extends VirAttr> virAttrs) {
+ final Set<String> virAttrNames = new HashSet<String>();
+ for (VirAttr attr : virAttrs) {
+ virAttrNames.add(attr.getSchema().getKey());
+ }
+ return virAttrNames;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/ImplementationClassNamesLoader.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/ImplementationClassNamesLoader.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/ImplementationClassNamesLoader.java
new file mode 100644
index 0000000..4219881
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/ImplementationClassNamesLoader.java
@@ -0,0 +1,141 @@
+/*
+ * 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.server.logic.init;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.lib.wrap.Validator;
+import org.apache.syncope.provisioning.api.job.PushJob;
+import org.apache.syncope.provisioning.api.job.SyncJob;
+import org.apache.syncope.provisioning.api.job.TaskJob;
+import org.apache.syncope.provisioning.api.propagation.PropagationActions;
+import org.apache.syncope.provisioning.api.sync.PushActions;
+import org.apache.syncope.provisioning.api.sync.SyncActions;
+import org.apache.syncope.provisioning.api.sync.SyncCorrelationRule;
+import org.apache.syncope.server.logic.report.Reportlet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.ClassMetadata;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Cache class names for all implementations of Syncope interfaces found in classpath, for later usage.
+ */
+@Component
+public class ImplementationClassNamesLoader {
+
+ public enum Type {
+
+ REPORTLET,
+ TASKJOB,
+ SYNC_ACTIONS,
+ PUSH_ACTIONS,
+ SYNC_CORRELATION_RULES,
+ PUSH_CORRELATION_RULES,
+ PROPAGATION_ACTIONS,
+ VALIDATOR
+
+ }
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(ImplementationClassNamesLoader.class);
+
+ @Autowired
+ private ResourcePatternResolver resResolver;
+
+ private Map<Type, Set<String>> classNames;
+
+ public void load() {
+ CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
+
+ classNames = new EnumMap<Type, Set<String>>(Type.class);
+ for (Type type : Type.values()) {
+ classNames.put(type, new HashSet<String>());
+ }
+
+ try {
+ for (Resource resource : resResolver.getResources("classpath*:**/*.class")) {
+ ClassMetadata metadata = factory.getMetadataReader(resource).getClassMetadata();
+
+ try {
+ Class<?> clazz = ClassUtils.forName(metadata.getClassName(), ClassUtils.getDefaultClassLoader());
+ Set<Class<?>> interfaces = ClassUtils.getAllInterfacesForClassAsSet(clazz);
+
+ if (interfaces.contains(Reportlet.class) && !metadata.isAbstract()) {
+ classNames.get(Type.REPORTLET).add(clazz.getName());
+ }
+
+ if ((interfaces.contains(TaskJob.class))
+ && !metadata.isAbstract()
+ && !SyncJob.class.getName().equals(metadata.getClassName())
+ && !PushJob.class.getName().equals(metadata.getClassName())) {
+
+ classNames.get(Type.TASKJOB).add(metadata.getClassName());
+ }
+
+ if (interfaces.contains(SyncActions.class) && !metadata.isAbstract()) {
+ classNames.get(Type.SYNC_ACTIONS).add(metadata.getClassName());
+ }
+
+ if (interfaces.contains(PushActions.class) && !metadata.isAbstract()) {
+ classNames.get(Type.PUSH_ACTIONS).add(metadata.getClassName());
+ }
+
+ if (interfaces.contains(SyncCorrelationRule.class) && !metadata.isAbstract()) {
+ classNames.get(Type.SYNC_CORRELATION_RULES).add(metadata.getClassName());
+ }
+
+ // TODO: add push correlation rules management
+ if (interfaces.contains(PropagationActions.class) && !metadata.isAbstract()) {
+ classNames.get(Type.PROPAGATION_ACTIONS).add(metadata.getClassName());
+ }
+
+ if (interfaces.contains(Validator.class) && !metadata.isAbstract()) {
+ classNames.get(Type.VALIDATOR).add(metadata.getClassName());
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("Could not load class {}", metadata.getClassName());
+ } catch (LinkageError e) {
+ LOG.warn("Could not link class {}", metadata.getClassName());
+ }
+ }
+ } catch (IOException e) {
+ LOG.error("While searching for implementatiom classes", e);
+ }
+
+ classNames = Collections.unmodifiableMap(classNames);
+
+ LOG.debug("Implementation classes found: {}", classNames);
+ }
+
+ public Set<String> getClassNames(final Type type) {
+ return classNames.get(type);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/JobInstanceLoader.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/JobInstanceLoader.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/JobInstanceLoader.java
new file mode 100644
index 0000000..8944777
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/JobInstanceLoader.java
@@ -0,0 +1,287 @@
+/*
+ * 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.server.logic.init;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.persistence.api.dao.ConfDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.ReportDAO;
+import org.apache.syncope.persistence.api.dao.TaskDAO;
+import org.apache.syncope.persistence.api.entity.Report;
+import org.apache.syncope.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.persistence.api.entity.task.PushTask;
+import org.apache.syncope.persistence.api.entity.task.SchedTask;
+import org.apache.syncope.persistence.api.entity.task.SyncTask;
+import org.apache.syncope.persistence.api.entity.task.Task;
+import org.apache.syncope.provisioning.api.job.SyncJob;
+import org.apache.syncope.provisioning.api.job.TaskJob;
+import org.apache.syncope.provisioning.api.sync.SyncActions;
+import org.apache.syncope.server.logic.notification.NotificationJob;
+import org.apache.syncope.server.logic.report.ReportJob;
+import org.apache.syncope.server.spring.ApplicationContextProvider;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.TriggerKey;
+import org.quartz.impl.JobDetailImpl;
+import org.quartz.impl.triggers.CronTriggerImpl;
+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.scheduling.quartz.SchedulerFactoryBean;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class JobInstanceLoader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JobInstanceLoader.class);
+
+ @Autowired
+ private SchedulerFactoryBean scheduler;
+
+ @Autowired
+ private TaskDAO taskDAO;
+
+ @Autowired
+ private ReportDAO reportDAO;
+
+ @Autowired
+ private ConfDAO confDAO;
+
+ private static Long getIdFromJobName(final String name, final String pattern, final int prefixLength) {
+ Long result = null;
+
+ Matcher jobMatcher = Pattern.compile(pattern).matcher(name);
+ if (jobMatcher.matches()) {
+ try {
+ result = Long.valueOf(name.substring(prefixLength));
+ } catch (NumberFormatException e) {
+ LOG.error("Unparsable id: {}", name.substring(prefixLength), e);
+ }
+ }
+
+ return result;
+ }
+
+ public static Long getTaskIdFromJobName(final String name) {
+ return getIdFromJobName("taskJob[0-9]+", name, 7);
+ }
+
+ public static Long getReportIdFromJobName(final String name) {
+ return getIdFromJobName("reportJob[0-9]+", name, 9);
+ }
+
+ public static String getJobName(final Task task) {
+ return task == null
+ ? "taskNotificationJob"
+ : "taskJob" + task.getKey();
+ }
+
+ public static String getJobName(final Report report) {
+ return "reportJob" + report.getKey();
+ }
+
+ public static String getTriggerName(final String jobName) {
+ return "Trigger_" + jobName;
+ }
+
+ private void registerJob(final String jobName, final Job jobInstance, final String cronExpression)
+ throws SchedulerException, ParseException {
+
+ synchronized (scheduler.getScheduler()) {
+ boolean jobAlreadyRunning = false;
+ for (JobExecutionContext jobCtx : scheduler.getScheduler().getCurrentlyExecutingJobs()) {
+ if (jobName.equals(jobCtx.getJobDetail().getKey().getName())
+ && Scheduler.DEFAULT_GROUP.equals(jobCtx.getJobDetail().getKey().getGroup())) {
+
+ jobAlreadyRunning = true;
+
+ LOG.debug("Job {} already running, cancel", jobCtx.getJobDetail().getKey());
+ }
+ }
+
+ if (jobAlreadyRunning) {
+ return;
+ }
+ }
+
+ // 0. unregister job
+ unregisterJob(jobName);
+
+ // 1. Job bean
+ ApplicationContextProvider.getBeanFactory().registerSingleton(jobName, jobInstance);
+
+ // 2. JobDetail bean
+ JobDetailImpl jobDetail = new JobDetailImpl();
+ jobDetail.setName(jobName);
+ jobDetail.setGroup(Scheduler.DEFAULT_GROUP);
+ jobDetail.setJobClass(jobInstance.getClass());
+
+ // 3. Trigger
+ if (cronExpression == null) {
+ // Jobs added with no trigger must be durable
+ jobDetail.setDurability(true);
+ scheduler.getScheduler().addJob(jobDetail, true);
+ } else {
+ CronTriggerImpl cronTrigger = new CronTriggerImpl();
+ cronTrigger.setName(getTriggerName(jobName));
+ cronTrigger.setCronExpression(cronExpression);
+
+ scheduler.getScheduler().scheduleJob(jobDetail, cronTrigger);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void registerJob(final Task task, final String jobClassName, final String cronExpression)
+ throws ClassNotFoundException, SchedulerException, ParseException {
+
+ final Class<?> jobClass = Class.forName(jobClassName);
+ Job jobInstance = (Job) ApplicationContextProvider.getBeanFactory().
+ createBean(jobClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ if (jobInstance instanceof TaskJob) {
+ ((TaskJob) jobInstance).setTaskId(task.getKey());
+ }
+
+ // In case of synchronization job/task retrieve and set synchronization actions:
+ // actions cannot be changed at runtime but connector and synchronization policies (reloaded at execution time).
+ if (jobInstance instanceof SyncJob && task instanceof SyncTask) {
+ final List<SyncActions> actions = new ArrayList<>();
+ for (String className : ((SyncTask) task).getActionsClassNames()) {
+ try {
+ Class<?> actionsClass = Class.forName(className);
+
+ final SyncActions syncActions =
+ (SyncActions) ApplicationContextProvider.getBeanFactory().
+ createBean(actionsClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, true);
+
+ actions.add(syncActions);
+ } catch (Exception e) {
+ LOG.info("Class '{}' not found", className, e);
+ }
+ }
+
+ ((SyncJob) jobInstance).setActions(actions);
+ }
+
+ registerJob(getJobName(task), jobInstance, cronExpression);
+ }
+
+ @Transactional(readOnly = true)
+ public void registerTaskJob(final Long taskId)
+ throws ClassNotFoundException, SchedulerException, ParseException {
+
+ SchedTask task = taskDAO.find(taskId);
+ if (task == null) {
+ throw new NotFoundException("Task " + taskId);
+ } else {
+ registerJob(task, task.getJobClassName(), task.getCronExpression());
+ }
+ }
+
+ public void registerJob(final Report report) throws SchedulerException, ParseException {
+ Job jobInstance = (Job) ApplicationContextProvider.getBeanFactory().
+ createBean(ReportJob.class, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ ((ReportJob) jobInstance).setReportKey(report.getKey());
+
+ registerJob(getJobName(report), jobInstance, report.getCronExpression());
+ }
+
+ @Transactional(readOnly = true)
+ public void registerReportJob(final Long reportId) throws SchedulerException, ParseException {
+ Report report = reportDAO.find(reportId);
+ if (report == null) {
+ throw new NotFoundException("Report " + reportId);
+ } else {
+ registerJob(report);
+ }
+ }
+
+ private void unregisterJob(final String jobName) {
+ try {
+ scheduler.getScheduler().unscheduleJob(new TriggerKey(jobName, Scheduler.DEFAULT_GROUP));
+ scheduler.getScheduler().deleteJob(new JobKey(jobName, Scheduler.DEFAULT_GROUP));
+ } catch (SchedulerException e) {
+ LOG.error("Could not remove job " + jobName, e);
+ }
+
+ if (ApplicationContextProvider.getBeanFactory().containsSingleton(jobName)) {
+ ApplicationContextProvider.getBeanFactory().destroySingleton(jobName);
+ }
+ }
+
+ public void unregisterJob(final Task task) {
+ unregisterJob(getJobName(task));
+ }
+
+ public void unregisterJob(final Report report) {
+ unregisterJob(getJobName(report));
+ }
+
+ @Transactional
+ public void load() {
+ // 1. jobs for SchedTasks
+ Set<SchedTask> tasks = new HashSet<>(taskDAO.<SchedTask>findAll(TaskType.SCHEDULED));
+ tasks.addAll(taskDAO.<SyncTask>findAll(TaskType.SYNCHRONIZATION));
+ tasks.addAll(taskDAO.<PushTask>findAll(TaskType.PUSH));
+ for (SchedTask task : tasks) {
+ try {
+ registerJob(task, task.getJobClassName(), task.getCronExpression());
+ } catch (Exception e) {
+ LOG.error("While loading job instance for task " + task.getKey(), e);
+ }
+ }
+
+ // 2. NotificationJob
+ CPlainAttr notificationJobCronExp =
+ confDAO.find("notificationjob.cronExpression", NotificationJob.DEFAULT_CRON_EXP);
+ if (StringUtils.isBlank(notificationJobCronExp.getValuesAsStrings().get(0))) {
+ LOG.debug("Empty value provided for NotificationJob's cron, not registering anything on Quartz");
+ } else {
+ LOG.debug("NotificationJob's cron expression: {} - registering Quartz job and trigger",
+ notificationJobCronExp);
+
+ try {
+ registerJob(null, NotificationJob.class.getName(), notificationJobCronExp.getValuesAsStrings().get(0));
+ } catch (Exception e) {
+ LOG.error("While loading NotificationJob instance", e);
+ }
+ }
+
+ // 3. ReportJobs
+ for (Report report : reportDAO.findAll()) {
+ try {
+ registerJob(report);
+ } catch (Exception e) {
+ LOG.error("While loading job instance for report " + report.getName(), e);
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/WorkflowAdapterLoader.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/WorkflowAdapterLoader.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/WorkflowAdapterLoader.java
new file mode 100644
index 0000000..5844277
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/init/WorkflowAdapterLoader.java
@@ -0,0 +1,88 @@
+/*
+ * 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.server.logic.init;
+
+import org.apache.syncope.server.workflow.api.RoleWorkflowAdapter;
+import org.apache.syncope.server.workflow.api.UserWorkflowAdapter;
+import org.apache.syncope.server.workflow.api.WorkflowInstanceLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class WorkflowAdapterLoader implements BeanFactoryAware {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WorkflowAdapterLoader.class);
+
+ @Autowired
+ private UserWorkflowAdapter uwfAdapter;
+
+ @Autowired
+ private RoleWorkflowAdapter rwfAdapter;
+
+ private DefaultListableBeanFactory beanFactory;
+
+ private WorkflowInstanceLoader wfLoader;
+
+ @Override
+ public void setBeanFactory(final BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = (DefaultListableBeanFactory) beanFactory;
+ }
+
+ private void lazyInit() {
+ if (wfLoader == null) {
+ if (uwfAdapter.getLoaderClass() != null) {
+ wfLoader = (WorkflowInstanceLoader) beanFactory.createBean(
+ uwfAdapter.getLoaderClass(), AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ }
+ if (rwfAdapter.getLoaderClass() != null) {
+ wfLoader = (WorkflowInstanceLoader) beanFactory.createBean(
+ rwfAdapter.getLoaderClass(), AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ }
+ }
+ }
+
+ public String getTablePrefix() {
+ lazyInit();
+ return wfLoader == null ? null : wfLoader.getTablePrefix();
+ }
+
+ public void init() {
+ lazyInit();
+ if (wfLoader != null) {
+ wfLoader.init();
+ }
+ }
+
+ public void load() {
+ lazyInit();
+ if (wfLoader == null) {
+ LOG.debug("Configured workflow adapter does not need loading");
+ } else {
+ LOG.debug("Loading workflow adapter by {}", wfLoader.getClass().getName());
+ wfLoader.load();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/notification/NotificationJob.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/notification/NotificationJob.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/notification/NotificationJob.java
new file mode 100644
index 0000000..77189e1
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/notification/NotificationJob.java
@@ -0,0 +1,280 @@
+/*
+ * 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.server.logic.notification;
+
+import java.util.Date;
+import java.util.Properties;
+import javax.mail.internet.MimeMessage;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.lib.types.AuditElements.Result;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.common.lib.types.TraceLevel;
+import org.apache.syncope.persistence.api.dao.TaskDAO;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.task.NotificationTask;
+import org.apache.syncope.persistence.api.entity.task.TaskExec;
+import org.apache.syncope.server.logic.audit.AuditManager;
+import org.apache.syncope.server.utils.ExceptionUtil;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.mail.javamail.MimeMessageHelper;
+
+/**
+ * Periodically checks for notification to send.
+ *
+ * @see NotificationTask
+ */
+@DisallowConcurrentExecution
+public class NotificationJob implements Job {
+
+ enum Status {
+
+ SENT,
+ NOT_SENT
+
+ }
+
+ public static final String DEFAULT_CRON_EXP = "0 0/5 * * * ?";
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(NotificationJob.class);
+
+ @Autowired
+ private AuditManager auditManager;
+
+ @Autowired
+ private NotificationManager notificationManager;
+
+ @Autowired
+ private JavaMailSender mailSender;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ /**
+ * Task DAO.
+ */
+ @Autowired
+ private TaskDAO taskDAO;
+
+ private long maxRetries;
+
+ private void init() {
+ maxRetries = notificationManager.getMaxRetries();
+
+ if (mailSender instanceof JavaMailSenderImpl
+ && StringUtils.isNotBlank(((JavaMailSenderImpl) mailSender).getUsername())) {
+
+ Properties javaMailProperties = ((JavaMailSenderImpl) mailSender).getJavaMailProperties();
+ javaMailProperties.setProperty("mail.smtp.auth", "true");
+ ((JavaMailSenderImpl) mailSender).setJavaMailProperties(javaMailProperties);
+ }
+ }
+
+ public TaskExec executeSingle(final NotificationTask task) {
+ init();
+
+ TaskExec execution = entityFactory.newEntity(TaskExec.class);
+ execution.setTask(task);
+ execution.setStartDate(new Date());
+
+ boolean retryPossible = true;
+
+ if (StringUtils.isBlank(task.getSubject()) || task.getRecipients().isEmpty()
+ || StringUtils.isBlank(task.getHtmlBody()) || StringUtils.isBlank(task.getTextBody())) {
+
+ String message = "Could not fetch all required information for sending e-mails:\n"
+ + task.getRecipients() + "\n"
+ + task.getSender() + "\n"
+ + task.getSubject() + "\n"
+ + task.getHtmlBody() + "\n"
+ + task.getTextBody();
+ LOG.error(message);
+
+ execution.setStatus(Status.NOT_SENT.name());
+ retryPossible = false;
+
+ if (task.getTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal()) {
+ execution.setMessage(message);
+ }
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("About to send e-mails:\n"
+ + task.getRecipients() + "\n"
+ + task.getSender() + "\n"
+ + task.getSubject() + "\n"
+ + task.getHtmlBody() + "\n"
+ + task.getTextBody() + "\n");
+ }
+
+ for (String to : task.getRecipients()) {
+ try {
+ MimeMessage message = mailSender.createMimeMessage();
+ MimeMessageHelper helper = new MimeMessageHelper(message, true);
+ helper.setTo(to);
+ helper.setFrom(task.getSender());
+ helper.setSubject(task.getSubject());
+ helper.setText(task.getTextBody(), task.getHtmlBody());
+
+ mailSender.send(message);
+
+ execution.setStatus(Status.SENT.name());
+
+ StringBuilder report = new StringBuilder();
+ switch (task.getTraceLevel()) {
+ case ALL:
+ report.append("FROM: ").append(task.getSender()).append('\n').
+ append("TO: ").append(to).append('\n').
+ append("SUBJECT: ").append(task.getSubject()).append('\n').append('\n').
+ append(task.getTextBody()).append('\n').append('\n').
+ append(task.getHtmlBody()).append('\n');
+ break;
+
+ case SUMMARY:
+ report.append("E-mail sent to ").append(to).append('\n');
+ break;
+
+ case FAILURES:
+ case NONE:
+ default:
+ }
+ if (report.length() > 0) {
+ execution.setMessage(report.toString());
+ }
+
+ auditManager.audit(
+ AuditElements.EventCategoryType.TASK,
+ "notification",
+ null,
+ "send",
+ Result.SUCCESS,
+ null,
+ null,
+ task,
+ "Successfully sent notification to " + to);
+ } catch (Exception e) {
+ LOG.error("Could not send e-mail", e);
+
+ execution.setStatus(Status.NOT_SENT.name());
+ if (task.getTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal()) {
+ execution.setMessage(ExceptionUtil.getFullStackTrace(e));
+ }
+
+ auditManager.audit(
+ AuditElements.EventCategoryType.TASK,
+ "notification",
+ null,
+ "send",
+ Result.FAILURE,
+ null,
+ null,
+ task,
+ "Could not send notification to " + to, e);
+ }
+
+ execution.setEndDate(new Date());
+ }
+ }
+
+ if (hasToBeRegistered(execution)) {
+ execution = notificationManager.storeExec(execution);
+ if (retryPossible && (Status.valueOf(execution.getStatus()) == Status.NOT_SENT)) {
+ handleRetries(execution);
+ }
+ } else {
+ notificationManager.setTaskExecuted(execution.getTask().getKey(), true);
+ }
+
+ return execution;
+ }
+
+ @Override
+ public void execute(final JobExecutionContext context)
+ throws JobExecutionException {
+
+ LOG.debug("Waking up...");
+
+ for (NotificationTask task : taskDAO.<NotificationTask>findToExec(TaskType.NOTIFICATION)) {
+ LOG.debug("Found notification task {} to be executed: starting...", task);
+ executeSingle(task);
+ LOG.debug("Notification task {} executed", task);
+ }
+
+ LOG.debug("Sleeping again...");
+ }
+
+ private boolean hasToBeRegistered(final TaskExec execution) {
+ NotificationTask task = (NotificationTask) execution.getTask();
+
+ // True if either failed and failures have to be registered, or if ALL
+ // has to be registered.
+ return (Status.valueOf(execution.getStatus()) == Status.NOT_SENT
+ && task.getTraceLevel().ordinal() >= TraceLevel.FAILURES.ordinal())
+ || task.getTraceLevel() == TraceLevel.ALL;
+ }
+
+ private void handleRetries(final TaskExec execution) {
+ if (maxRetries <= 0) {
+ return;
+ }
+
+ long failedExecutionsCount = notificationManager.countExecutionsWithStatus(
+ execution.getTask().getKey(), Status.NOT_SENT.name());
+
+ if (failedExecutionsCount <= maxRetries) {
+ LOG.debug("Execution of notification task {} will be retried [{}/{}]",
+ execution.getTask(), failedExecutionsCount, maxRetries);
+ notificationManager.setTaskExecuted(execution.getTask().getKey(), false);
+
+ auditManager.audit(
+ AuditElements.EventCategoryType.TASK,
+ "notification",
+ null,
+ "retry",
+ Result.SUCCESS,
+ null,
+ null,
+ execution,
+ "Notification task " + execution.getTask().getKey() + " will be retried");
+ } else {
+ LOG.error("Maximum number of retries reached for task {} - giving up", execution.getTask());
+
+ auditManager.audit(
+ AuditElements.EventCategoryType.TASK,
+ "notification",
+ null,
+ "retry",
+ Result.FAILURE,
+ null,
+ null,
+ execution,
+ "Giving up retries on notification task " + execution.getTask().getKey());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/notification/NotificationManager.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/notification/NotificationManager.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/notification/NotificationManager.java
new file mode 100644
index 0000000..68c3a78
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/notification/NotificationManager.java
@@ -0,0 +1,441 @@
+/*
+ * 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.server.logic.notification;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.lib.types.AuditElements.Result;
+import org.apache.syncope.common.lib.types.AuditLoggerName;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.persistence.api.RoleEntitlementUtil;
+import org.apache.syncope.persistence.api.dao.ConfDAO;
+import org.apache.syncope.persistence.api.dao.EntitlementDAO;
+import org.apache.syncope.persistence.api.dao.NotificationDAO;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.dao.SubjectSearchDAO;
+import org.apache.syncope.persistence.api.dao.TaskDAO;
+import org.apache.syncope.persistence.api.dao.UserDAO;
+import org.apache.syncope.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.persistence.api.entity.Attributable;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.Notification;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+import org.apache.syncope.persistence.api.entity.Subject;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.task.NotificationTask;
+import org.apache.syncope.persistence.api.entity.task.TaskExec;
+import org.apache.syncope.persistence.api.entity.user.UDerAttr;
+import org.apache.syncope.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.persistence.api.entity.user.UVirAttr;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.server.logic.data.RoleDataBinder;
+import org.apache.syncope.server.logic.data.UserDataBinder;
+import org.apache.syncope.server.logic.search.SearchCondConverter;
+import org.apache.syncope.server.utils.ConnObjectUtil;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.exception.VelocityException;
+import org.apache.velocity.tools.ToolManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Create notification tasks that will be executed by NotificationJob.
+ *
+ * @see NotificationTask
+ */
+@Transactional(rollbackFor = { Throwable.class })
+public class NotificationManager {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(NotificationManager.class);
+
+ public static final String MAIL_TEMPLATES = "mailTemplates/";
+
+ public static final String MAIL_TEMPLATE_HTML_SUFFIX = ".html.vm";
+
+ public static final String MAIL_TEMPLATE_TEXT_SUFFIX = ".txt.vm";
+
+ /**
+ * Notification DAO.
+ */
+ @Autowired
+ private NotificationDAO notificationDAO;
+
+ /**
+ * Configuration DAO.
+ */
+ @Autowired
+ private ConfDAO confDAO;
+
+ /**
+ * User DAO.
+ */
+ @Autowired
+ private UserDAO userDAO;
+
+ /**
+ * Role DAO.
+ */
+ @Autowired
+ private RoleDAO roleDAO;
+
+ /**
+ * User data binder.
+ */
+ @Autowired
+ private UserDataBinder userDataBinder;
+
+ /**
+ * Role data binder.
+ */
+ @Autowired
+ private RoleDataBinder roleDataBinder;
+
+ /**
+ * User Search DAO.
+ */
+ @Autowired
+ private SubjectSearchDAO searchDAO;
+
+ /**
+ * Task DAO.
+ */
+ @Autowired
+ private TaskDAO taskDAO;
+
+ /**
+ * Velocity template engine.
+ */
+ @Autowired
+ private VelocityEngine velocityEngine;
+
+ /**
+ * Velocity tool manager.
+ */
+ @Autowired
+ private ToolManager velocityToolManager;
+
+ @Autowired
+ private EntitlementDAO entitlementDAO;
+
+ @Autowired
+ private ConnObjectUtil connObjectUtil;
+
+ @Autowired
+ private EntityFactory entityFactory;
+
+ @Autowired
+ private AttributableUtilFactory attrUtilFactory;
+
+ @Transactional(readOnly = true)
+ public long getMaxRetries() {
+ return confDAO.find("notification.maxRetries", "0").getValues().get(0).getLongValue();
+ }
+
+ /**
+ * Create a notification task.
+ *
+ * @param notification notification to take as model
+ * @param attributable the user this task is about
+ * @param model Velocity model
+ * @return notification task, fully populated
+ */
+ private NotificationTask getNotificationTask(
+ final Notification notification,
+ final Attributable<?, ?, ?> attributable,
+ final Map<String, Object> model) {
+
+ if (attributable != null) {
+ connObjectUtil.retrieveVirAttrValues(attributable,
+ attrUtilFactory.getInstance(
+ attributable instanceof User ? AttributableType.USER : AttributableType.ROLE));
+ }
+
+ final List<User> recipients = new ArrayList<>();
+
+ if (notification.getRecipients() != null) {
+ recipients.addAll(searchDAO.<User>search(RoleEntitlementUtil.getRoleKeys(entitlementDAO.findAll()),
+ SearchCondConverter.convert(notification.getRecipients()),
+ Collections.<OrderByClause>emptyList(), SubjectType.USER));
+ }
+
+ if (notification.isSelfAsRecipient() && attributable instanceof User) {
+ recipients.add((User) attributable);
+ }
+
+ final Set<String> recipientEmails = new HashSet<>();
+ final List<UserTO> recipientTOs = new ArrayList<>(recipients.size());
+ for (User recipient : recipients) {
+ connObjectUtil.retrieveVirAttrValues(recipient, attrUtilFactory.getInstance(AttributableType.USER));
+
+ String email = getRecipientEmail(notification.getRecipientAttrType(),
+ notification.getRecipientAttrName(), recipient);
+ if (email == null) {
+ LOG.warn("{} cannot be notified: {} not found", recipient, notification.getRecipientAttrName());
+ } else {
+ recipientEmails.add(email);
+ recipientTOs.add(userDataBinder.getUserTO(recipient));
+ }
+ }
+
+ if (notification.getStaticRecipients() != null) {
+ recipientEmails.addAll(notification.getStaticRecipients());
+ }
+
+ model.put("recipients", recipientTOs);
+ model.put("syncopeConf", this.findAllSyncopeConfs());
+ model.put("events", notification.getEvents());
+
+ NotificationTask task = entityFactory.newEntity(NotificationTask.class);
+ task.setTraceLevel(notification.getTraceLevel());
+ task.getRecipients().addAll(recipientEmails);
+ task.setSender(notification.getSender());
+ task.setSubject(notification.getSubject());
+
+ String htmlBody = mergeTemplateIntoString(
+ MAIL_TEMPLATES + notification.getTemplate() + MAIL_TEMPLATE_HTML_SUFFIX, model);
+ String textBody = mergeTemplateIntoString(
+ MAIL_TEMPLATES + notification.getTemplate() + MAIL_TEMPLATE_TEXT_SUFFIX, model);
+
+ task.setHtmlBody(htmlBody);
+ task.setTextBody(textBody);
+
+ return task;
+ }
+
+ private String mergeTemplateIntoString(final String templateLocation, final Map<String, Object> model) {
+ StringWriter result = new StringWriter();
+ try {
+ Context velocityContext = createVelocityContext(model);
+ velocityEngine.mergeTemplate(templateLocation, SyncopeConstants.DEFAULT_ENCODING, velocityContext, result);
+ } catch (VelocityException e) {
+ LOG.error("Could not get mail body", e);
+ } catch (RuntimeException e) {
+ // ensure same behaviour as by using Spring VelocityEngineUtils.mergeTemplateIntoString()
+ throw e;
+ } catch (Exception e) {
+ LOG.error("Could not get mail body", e);
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Create a Velocity Context for the given model, to be passed to the template for merging.
+ *
+ * @param model Velocity model
+ * @return Velocity context
+ */
+ protected Context createVelocityContext(Map<String, Object> model) {
+ Context toolContext = velocityToolManager.createContext();
+ return new VelocityContext(model, toolContext);
+ }
+
+ /**
+ * Create notification tasks for each notification matching the given user id and (some of) tasks performed.
+ */
+ public void createTasks(
+ final AuditElements.EventCategoryType type,
+ final String category,
+ final String subcategory,
+ final String event,
+ final Result condition,
+ final Object before,
+ final Object output,
+ final Object... input) {
+
+ SubjectType subjectType = null;
+ Subject<?, ?, ?> subject = null;
+
+ if (before instanceof UserTO) {
+ subjectType = SubjectType.USER;
+ subject = userDAO.find(((UserTO) before).getKey());
+ } else if (output instanceof UserTO) {
+ subjectType = SubjectType.USER;
+ subject = userDAO.find(((UserTO) output).getKey());
+ } else if (before instanceof RoleTO) {
+ subjectType = SubjectType.ROLE;
+ subject = roleDAO.find(((RoleTO) before).getKey());
+ } else if (output instanceof RoleTO) {
+ subjectType = SubjectType.ROLE;
+ subject = roleDAO.find(((RoleTO) output).getKey());
+ }
+
+ LOG.debug("Search notification for [{}]{}", subjectType, subject);
+
+ for (Notification notification : notificationDAO.findAll()) {
+ LOG.debug("Notification available user about {}", notification.getUserAbout());
+ LOG.debug("Notification available role about {}", notification.getRoleAbout());
+ if (notification.isActive()) {
+
+ final Set<String> events = new HashSet<>(notification.getEvents());
+ events.retainAll(Collections.<String>singleton(AuditLoggerName.buildEvent(
+ type, category, subcategory, event, condition)));
+
+ if (events.isEmpty()) {
+ LOG.debug("No events found about {}", subject);
+ } else if (subjectType == null || subject == null
+ || notification.getUserAbout() == null || notification.getRoleAbout() == null
+ || searchDAO.matches(subject,
+ SearchCondConverter.convert(notification.getUserAbout()), subjectType)
+ || searchDAO.matches(subject,
+ SearchCondConverter.convert(notification.getRoleAbout()), subjectType)) {
+
+ LOG.debug("Creating notification task for events {} about {}", events, subject);
+
+ final Map<String, Object> model = new HashMap<>();
+ model.put("type", type);
+ model.put("category", category);
+ model.put("subcategory", subcategory);
+ model.put("event", event);
+ model.put("condition", condition);
+ model.put("before", before);
+ model.put("output", output);
+ model.put("input", input);
+
+ if (subject instanceof User) {
+ model.put("user", userDataBinder.getUserTO((User) subject));
+ } else if (subject instanceof Role) {
+ model.put("role", roleDataBinder.getRoleTO((Role) subject));
+ }
+
+ taskDAO.save(getNotificationTask(notification, subject, model));
+ }
+ } else {
+ LOG.debug("Notification {}, userAbout {}, roleAbout {} is deactivated, "
+ + "notification task will not be created", notification.getKey(),
+ notification.getUserAbout(), notification.getRoleAbout());
+ }
+ }
+ }
+
+ private String getRecipientEmail(
+ final IntMappingType recipientAttrType, final String recipientAttrName, final User user) {
+
+ String email = null;
+
+ switch (recipientAttrType) {
+ case Username:
+ email = user.getUsername();
+ break;
+
+ case UserSchema:
+ UPlainAttr attr = user.getPlainAttr(recipientAttrName);
+ if (attr != null && !attr.getValuesAsStrings().isEmpty()) {
+ email = attr.getValuesAsStrings().get(0);
+ }
+ break;
+
+ case UserVirtualSchema:
+ UVirAttr virAttr = user.getVirAttr(recipientAttrName);
+ if (virAttr != null && !virAttr.getValues().isEmpty()) {
+ email = virAttr.getValues().get(0);
+ }
+ break;
+
+ case UserDerivedSchema:
+ UDerAttr derAttr = user.getDerAttr(recipientAttrName);
+ if (derAttr != null) {
+ email = derAttr.getValue(user.getPlainAttrs());
+ }
+ break;
+
+ default:
+ }
+
+ return email;
+ }
+
+ /**
+ * Store execution of a NotificationTask.
+ *
+ * @param execution task execution.
+ * @return merged task execution.
+ */
+ public TaskExec storeExec(final TaskExec execution) {
+ NotificationTask task = taskDAO.find(execution.getTask().getKey());
+ task.addExec(execution);
+ task.setExecuted(true);
+ taskDAO.save(task);
+ // this flush call is needed to generate a value for the execution id
+ taskDAO.flush();
+ return execution;
+ }
+
+ /**
+ * Set execution state of NotificationTask with provided id.
+ *
+ * @param taskId task to be updated
+ * @param executed execution state
+ */
+ public void setTaskExecuted(final Long taskId, final boolean executed) {
+ NotificationTask task = taskDAO.find(taskId);
+ task.setExecuted(executed);
+ taskDAO.save(task);
+ }
+
+ /**
+ * Count the number of task executions of a given task with a given status.
+ *
+ * @param taskId task id
+ * @param status status
+ * @return number of task executions
+ */
+ public long countExecutionsWithStatus(final Long taskId, final String status) {
+ NotificationTask task = taskDAO.find(taskId);
+ long count = 0;
+ for (TaskExec taskExec : task.getExecs()) {
+ if (status == null) {
+ if (taskExec.getStatus() == null) {
+ count++;
+ }
+ } else if (status.equals(taskExec.getStatus())) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ protected Map<String, String> findAllSyncopeConfs() {
+ Map<String, String> syncopeConfMap = new HashMap<>();
+ for (PlainAttr attr : confDAO.get().getPlainAttrs()) {
+ syncopeConfMap.put(attr.getSchema().getKey(), attr.getValuesAsStrings().get(0));
+ }
+ return syncopeConfMap;
+ }
+}
[04/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPAConfDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPAConfDAO.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPAConfDAO.java
index d38b1cd..5e7bc83 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPAConfDAO.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPAConfDAO.java
@@ -22,10 +22,10 @@ import org.apache.syncope.common.lib.types.AttributableType;
import org.apache.syncope.persistence.api.dao.ConfDAO;
import org.apache.syncope.persistence.api.dao.PlainAttrDAO;
import org.apache.syncope.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
import org.apache.syncope.persistence.api.entity.conf.CPlainAttr;
import org.apache.syncope.persistence.api.entity.conf.CPlainSchema;
import org.apache.syncope.persistence.api.entity.conf.Conf;
-import org.apache.syncope.persistence.jpa.entity.JPAAttributableUtil;
import org.apache.syncope.persistence.jpa.entity.conf.JPACPlainAttr;
import org.apache.syncope.persistence.jpa.entity.conf.JPAConf;
import org.springframework.beans.factory.annotation.Autowired;
@@ -41,6 +41,9 @@ public class JPAConfDAO extends AbstractDAO<Conf, Long> implements ConfDAO {
@Autowired
private PlainAttrDAO attrDAO;
+ @Autowired
+ private AttributableUtilFactory attrUtilFactory;
+
@Override
public Conf get() {
Conf instance = entityManager.find(JPAConf.class, 1L);
@@ -68,7 +71,7 @@ public class JPAConfDAO extends AbstractDAO<Conf, Long> implements ConfDAO {
result = new JPACPlainAttr();
result.setSchema(schemaDAO.find(key, CPlainSchema.class));
- result.addValue(defaultValue, JPAAttributableUtil.getInstance(AttributableType.CONFIGURATION));
+ result.addValue(defaultValue, attrUtilFactory.getInstance(AttributableType.CONFIGURATION));
}
return result;
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPARoleDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPARoleDAO.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPARoleDAO.java
index 5e6209c..8ac1423 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPARoleDAO.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPARoleDAO.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
@@ -31,12 +32,14 @@ import org.apache.syncope.common.lib.types.PolicyType;
import org.apache.syncope.persistence.api.RoleEntitlementUtil;
import org.apache.syncope.persistence.api.dao.DerAttrDAO;
import org.apache.syncope.persistence.api.dao.EntitlementDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
import org.apache.syncope.persistence.api.dao.PlainAttrDAO;
import org.apache.syncope.persistence.api.dao.RoleDAO;
import org.apache.syncope.persistence.api.dao.UserDAO;
import org.apache.syncope.persistence.api.dao.VirAttrDAO;
import org.apache.syncope.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.persistence.api.entity.AttrTemplate;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
import org.apache.syncope.persistence.api.entity.DerAttr;
import org.apache.syncope.persistence.api.entity.Entitlement;
import org.apache.syncope.persistence.api.entity.ExternalResource;
@@ -60,9 +63,10 @@ import org.apache.syncope.persistence.api.entity.role.RVirAttr;
import org.apache.syncope.persistence.api.entity.role.RVirAttrTemplate;
import org.apache.syncope.persistence.api.entity.role.Role;
import org.apache.syncope.persistence.api.entity.user.User;
-import org.apache.syncope.persistence.jpa.entity.JPAAttributableUtil;
import org.apache.syncope.persistence.jpa.entity.membership.JPAMembership;
import org.apache.syncope.persistence.jpa.entity.role.JPARole;
+import org.apache.syncope.server.security.AuthContextUtil;
+import org.apache.syncope.server.security.UnauthorizedRoleException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@@ -85,6 +89,9 @@ public class JPARoleDAO extends AbstractSubjectDAO<RPlainAttr, RDerAttr, RVirAtt
@Autowired
private EntitlementDAO entitlementDAO;
+ @Autowired
+ private AttributableUtilFactory attrUtilFactory;
+
@Override
protected Subject<RPlainAttr, RDerAttr, RVirAttr> findInternal(final Long key) {
return find(key);
@@ -321,27 +328,27 @@ public class JPARoleDAO extends AbstractSubjectDAO<RPlainAttr, RDerAttr, RVirAtt
@Override
public List<Role> findByAttrValue(final String schemaName, final RPlainAttrValue attrValue) {
return (List<Role>) findByAttrValue(
- schemaName, attrValue, JPAAttributableUtil.getInstance(AttributableType.ROLE));
+ schemaName, attrValue, attrUtilFactory.getInstance(AttributableType.ROLE));
}
@SuppressWarnings("unchecked")
@Override
public Role findByAttrUniqueValue(final String schemaName, final RPlainAttrValue attrUniqueValue) {
return (Role) findByAttrUniqueValue(schemaName, attrUniqueValue,
- JPAAttributableUtil.getInstance(AttributableType.ROLE));
+ attrUtilFactory.getInstance(AttributableType.ROLE));
}
@SuppressWarnings("unchecked")
@Override
public List<Role> findByDerAttrValue(final String schemaName, final String value) {
return (List<Role>) findByDerAttrValue(
- schemaName, value, JPAAttributableUtil.getInstance(AttributableType.ROLE));
+ schemaName, value, attrUtilFactory.getInstance(AttributableType.ROLE));
}
@SuppressWarnings("unchecked")
@Override
public List<Role> findByResource(final ExternalResource resource) {
- return (List<Role>) findByResource(resource, JPAAttributableUtil.getInstance(AttributableType.ROLE));
+ return (List<Role>) findByResource(resource, attrUtilFactory.getInstance(AttributableType.ROLE));
}
@Override
@@ -528,4 +535,23 @@ public class JPARoleDAO extends AbstractSubjectDAO<RPlainAttr, RDerAttr, RVirAtt
delete(role);
}
+
+ @Override
+ public Role authFetchRole(Long key) {
+ if (key == null) {
+ throw new NotFoundException("Null role id");
+ }
+
+ Role role = find(key);
+ if (role == null) {
+ throw new NotFoundException("Role " + key);
+ }
+
+ Set<Long> allowedRoleIds = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
+ if (!allowedRoleIds.contains(role.getKey())) {
+ throw new UnauthorizedRoleException(role.getKey());
+ }
+ return role;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPASubjectSearchDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPASubjectSearchDAO.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPASubjectSearchDAO.java
index 86e596f..e71488d 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPASubjectSearchDAO.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPASubjectSearchDAO.java
@@ -46,10 +46,10 @@ import org.apache.syncope.persistence.api.dao.search.ResourceCond;
import org.apache.syncope.persistence.api.dao.search.SearchCond;
import org.apache.syncope.persistence.api.dao.search.SubjectCond;
import org.apache.syncope.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
import org.apache.syncope.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.persistence.api.entity.PlainSchema;
import org.apache.syncope.persistence.api.entity.Subject;
-import org.apache.syncope.persistence.jpa.entity.JPAAttributableUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@@ -69,6 +69,9 @@ public class JPASubjectSearchDAO extends AbstractDAO<Subject<?, ?, ?>, Long> imp
@Autowired
private PlainSchemaDAO schemaDAO;
+ @Autowired
+ private AttributableUtilFactory attrUtilFactory;
+
private String getAdminRolesFilter(final Set<Long> adminRoles, final SubjectType type) {
final StringBuilder adminRolesFilter = new StringBuilder();
@@ -272,7 +275,7 @@ public class JPASubjectSearchDAO extends AbstractDAO<Subject<?, ?, ?>, Long> imp
private OrderBySupport parseOrderBy(final SubjectType type, final SearchSupport svs,
final List<OrderByClause> orderByClauses) {
- final AttributableUtil attrUtil = JPAAttributableUtil.getInstance(type.asAttributableType());
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(type.asAttributableType());
OrderBySupport orderBySupport = new OrderBySupport();
@@ -598,7 +601,7 @@ public class JPASubjectSearchDAO extends AbstractDAO<Subject<?, ?, ?>, Long> imp
private String getQuery(final AttributeCond cond, final boolean not, final List<Object> parameters,
final SubjectType type, final SearchSupport svs) {
- final AttributableUtil attrUtil = JPAAttributableUtil.getInstance(type.asAttributableType());
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(type.asAttributableType());
PlainSchema schema = schemaDAO.find(cond.getSchema(), attrUtil.plainSchemaClass());
if (schema == null) {
@@ -647,7 +650,7 @@ public class JPASubjectSearchDAO extends AbstractDAO<Subject<?, ?, ?>, Long> imp
private String getQuery(final SubjectCond cond, final boolean not, final List<Object> parameters,
final SubjectType type, final SearchSupport svs) {
- final AttributableUtil attrUtil = JPAAttributableUtil.getInstance(type.asAttributableType());
+ final AttributableUtil attrUtil = attrUtilFactory.getInstance(type.asAttributableType());
Field subjectField = ReflectionUtils.findField(attrUtil.attributableClass(), cond.getSchema());
if (subjectField == null) {
@@ -664,7 +667,7 @@ public class JPASubjectSearchDAO extends AbstractDAO<Subject<?, ?, ?>, Long> imp
}
// Deal with subject Integer fields logically mapping to boolean values
- // (SyncopeRole.inheritAttrs, for example)
+ // (SyncopeRole.inheritPlainAttrs, for example)
boolean foundBooleanMin = false;
boolean foundBooleanMax = false;
if (Integer.class.equals(subjectField.getType())) {
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPAUserDAO.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPAUserDAO.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPAUserDAO.java
index 2c141a6..fd28fcd 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPAUserDAO.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/dao/JPAUserDAO.java
@@ -21,10 +21,13 @@ package org.apache.syncope.persistence.jpa.dao;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import javax.annotation.Resource;
import javax.persistence.NoResultException;
import javax.persistence.TypedQuery;
import org.apache.syncope.common.lib.types.AttributableType;
import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.persistence.api.RoleEntitlementUtil;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
import org.apache.syncope.persistence.api.dao.RoleDAO;
import org.apache.syncope.persistence.api.dao.SubjectSearchDAO;
import org.apache.syncope.persistence.api.dao.UserDAO;
@@ -32,6 +35,7 @@ import org.apache.syncope.persistence.api.dao.search.AttributeCond;
import org.apache.syncope.persistence.api.dao.search.OrderByClause;
import org.apache.syncope.persistence.api.dao.search.SearchCond;
import org.apache.syncope.persistence.api.dao.search.SubjectCond;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
import org.apache.syncope.persistence.api.entity.ExternalResource;
import org.apache.syncope.persistence.api.entity.Subject;
import org.apache.syncope.persistence.api.entity.VirAttr;
@@ -42,8 +46,9 @@ import org.apache.syncope.persistence.api.entity.user.UPlainAttr;
import org.apache.syncope.persistence.api.entity.user.UPlainAttrValue;
import org.apache.syncope.persistence.api.entity.user.UVirAttr;
import org.apache.syncope.persistence.api.entity.user.User;
-import org.apache.syncope.persistence.jpa.entity.JPAAttributableUtil;
import org.apache.syncope.persistence.jpa.entity.user.JPAUser;
+import org.apache.syncope.server.security.AuthContextUtil;
+import org.apache.syncope.server.security.UnauthorizedRoleException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@@ -56,6 +61,12 @@ public class JPAUserDAO extends AbstractSubjectDAO<UPlainAttr, UDerAttr, UVirAtt
@Autowired
private RoleDAO roleDAO;
+ @Resource(name = "anonymousUser")
+ private String anonymousUser;
+
+ @Autowired
+ private AttributableUtilFactory attrUtilFactory;
+
@Override
protected Subject<UPlainAttr, UDerAttr, UVirAttr> findInternal(Long key) {
return find(key);
@@ -138,27 +149,27 @@ public class JPAUserDAO extends AbstractSubjectDAO<UPlainAttr, UDerAttr, UVirAtt
@Override
public List<User> findByAttrValue(final String schemaName, final UPlainAttrValue attrValue) {
return (List<User>) findByAttrValue(
- schemaName, attrValue, JPAAttributableUtil.getInstance(AttributableType.USER));
+ schemaName, attrValue, attrUtilFactory.getInstance(AttributableType.USER));
}
@SuppressWarnings("unchecked")
@Override
public User findByAttrUniqueValue(final String schemaName, final UPlainAttrValue attrUniqueValue) {
return (User) findByAttrUniqueValue(schemaName, attrUniqueValue,
- JPAAttributableUtil.getInstance(AttributableType.USER));
+ attrUtilFactory.getInstance(AttributableType.USER));
}
@SuppressWarnings("unchecked")
@Override
public List<User> findByDerAttrValue(final String schemaName, final String value) {
return (List<User>) findByDerAttrValue(
- schemaName, value, JPAAttributableUtil.getInstance(AttributableType.USER));
+ schemaName, value, attrUtilFactory.getInstance(AttributableType.USER));
}
@SuppressWarnings("unchecked")
@Override
public List<User> findByResource(final ExternalResource resource) {
- return (List<User>) findByResource(resource, JPAAttributableUtil.getInstance(AttributableType.USER));
+ return (List<User>) findByResource(resource, attrUtilFactory.getInstance(AttributableType.USER));
}
@Override
@@ -222,4 +233,52 @@ public class JPAUserDAO extends AbstractSubjectDAO<UPlainAttr, UDerAttr, UVirAtt
entityManager.remove(user);
}
+
+ private void securityChecks(final User user) {
+ // Allows anonymous (during self-registration) and self (during self-update) to read own SyncopeUser,
+ // otherwise goes thorugh security checks to see if needed role entitlements are owned
+ if (!AuthContextUtil.getAuthenticatedUsername().equals(anonymousUser)
+ && !AuthContextUtil.getAuthenticatedUsername().equals(user.getUsername())) {
+
+ Set<Long> roleIds = user.getRoleIds();
+ Set<Long> adminRoleIds = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
+ roleIds.removeAll(adminRoleIds);
+ if (!roleIds.isEmpty()) {
+ throw new UnauthorizedRoleException(roleIds);
+ }
+ }
+ }
+
+ @Override
+ public User authFecthUser(final Long key) {
+ if (key == null) {
+ throw new NotFoundException("Null user id");
+ }
+
+ User user = find(key);
+ if (user == null) {
+ throw new NotFoundException("User " + key);
+ }
+
+ securityChecks(user);
+
+ return user;
+ }
+
+ @Override
+ public User authFecthUser(final String username) {
+ if (username == null) {
+ throw new NotFoundException("Null username");
+ }
+
+ User user = find(username);
+ if (user == null) {
+ throw new NotFoundException("User " + username);
+ }
+
+ securityChecks(user);
+
+ return user;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/AbstractEntity.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/AbstractEntity.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/AbstractEntity.java
index 720b62b..8bde455 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/AbstractEntity.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/AbstractEntity.java
@@ -19,7 +19,6 @@
package org.apache.syncope.persistence.jpa.entity;
import java.beans.PropertyDescriptor;
-import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashSet;
@@ -31,7 +30,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
-public abstract class AbstractEntity<KEY> implements Entity<KEY>, Serializable {
+public abstract class AbstractEntity<KEY> implements Entity<KEY> {
private static final long serialVersionUID = -9017214159540857901L;
@@ -41,7 +40,7 @@ public abstract class AbstractEntity<KEY> implements Entity<KEY>, Serializable {
protected static final Logger LOG = LoggerFactory.getLogger(AbstractEntity.class);
protected void checkType(final Object object, final Class<?> clazz) {
- if (object !=null && !clazz.isInstance(object)) {
+ if (object != null && !clazz.isInstance(object)) {
throw new ClassCastException("Expected " + clazz.getName() + ", got " + object.getClass().getName());
}
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAAttributableUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAAttributableUtil.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAAttributableUtil.java
index 2705285..8b42b17 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAAttributableUtil.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAAttributableUtil.java
@@ -21,6 +21,12 @@ package org.apache.syncope.persistence.jpa.entity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.common.lib.to.ConfTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
import org.apache.syncope.common.lib.types.AttributableType;
import org.apache.syncope.common.lib.types.IntMappingType;
import org.apache.syncope.common.lib.types.MappingPurpose;
@@ -36,10 +42,6 @@ import org.apache.syncope.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.persistence.api.entity.PlainSchema;
import org.apache.syncope.persistence.api.entity.VirAttr;
import org.apache.syncope.persistence.api.entity.VirSchema;
-import org.apache.syncope.persistence.api.entity.conf.Conf;
-import org.apache.syncope.persistence.api.entity.membership.Membership;
-import org.apache.syncope.persistence.api.entity.role.Role;
-import org.apache.syncope.persistence.api.entity.user.User;
import org.apache.syncope.persistence.jpa.entity.conf.JPACPlainAttr;
import org.apache.syncope.persistence.jpa.entity.conf.JPACPlainAttrUniqueValue;
import org.apache.syncope.persistence.jpa.entity.conf.JPACPlainAttrValue;
@@ -81,7 +83,6 @@ import org.apache.syncope.persistence.jpa.entity.user.JPAUVirAttr;
import org.apache.syncope.persistence.jpa.entity.user.JPAUVirSchema;
import org.apache.syncope.persistence.jpa.entity.user.JPAUser;
import org.apache.syncope.server.spring.BeanUtils;
-import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.Uid;
import org.slf4j.LoggerFactory;
@@ -93,55 +94,9 @@ public class JPAAttributableUtil implements AttributableUtil {
*/
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(AttributableUtil.class);
- public static AttributableUtil getInstance(final AttributableType type) {
- return new JPAAttributableUtil(type);
- }
-
- public static AttributableUtil valueOf(final String name) {
- return new JPAAttributableUtil(AttributableType.valueOf(name));
- }
-
- public static AttributableUtil getInstance(final ObjectClass objectClass) {
- AttributableType type = null;
- if (ObjectClass.ACCOUNT.equals(objectClass)) {
- type = AttributableType.USER;
- }
- if (ObjectClass.GROUP.equals(objectClass)) {
- type = AttributableType.ROLE;
- }
-
- if (type == null) {
- throw new IllegalArgumentException("ObjectClass not supported: " + objectClass);
- }
-
- return new JPAAttributableUtil(type);
- }
-
- public static AttributableUtil getInstance(final Attributable attributable) {
- AttributableType type = null;
- if (attributable instanceof User) {
- type = AttributableType.USER;
- }
- if (attributable instanceof Role) {
- type = AttributableType.ROLE;
- }
- if (attributable instanceof Membership) {
- type = AttributableType.MEMBERSHIP;
- }
- if (attributable instanceof Conf) {
- type = AttributableType.CONFIGURATION;
- }
-
- if (type == null) {
- throw new IllegalArgumentException("Attributable type not supported: " + attributable.getClass().getName());
- }
-
- return new JPAAttributableUtil(type);
- }
-
private final AttributableType type;
- private JPAAttributableUtil(final AttributableType type) {
+ protected JPAAttributableUtil(final AttributableType type) {
this.type = type;
}
@@ -723,7 +678,7 @@ public class JPAAttributableUtil implements AttributableUtil {
}
}
- final List<T> result = new ArrayList<T>();
+ final List<T> result = new ArrayList<>();
switch (purpose) {
case SYNCHRONIZATION:
@@ -879,4 +834,46 @@ public class JPAAttributableUtil implements AttributableUtil {
return result;
}
+ @Override
+ public <T extends AbstractAttributableTO> T newAttributableTO() {
+ T result = null;
+
+ switch (type) {
+ case USER:
+ result = (T) new UserTO();
+ break;
+ case ROLE:
+ result = (T) new RoleTO();
+ break;
+ case MEMBERSHIP:
+ result = (T) new MembershipTO();
+ break;
+ case CONFIGURATION:
+ result = (T) new ConfTO();
+ break;
+ default:
+ }
+
+ return result;
+ }
+
+ @Override
+ public <T extends AbstractSubjectTO> T newSubjectTO() {
+ T result = null;
+
+ switch (type) {
+ case USER:
+ result = (T) new UserTO();
+ break;
+ case ROLE:
+ result = (T) new RoleTO();
+ break;
+ case MEMBERSHIP:
+ case CONFIGURATION:
+ default:
+ break;
+ }
+
+ return result;
+ }
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAEntityFactory.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAEntityFactory.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAEntityFactory.java
index c404c53..8e772b8 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAEntityFactory.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAEntityFactory.java
@@ -20,6 +20,7 @@ package org.apache.syncope.persistence.jpa.entity;
import org.apache.syncope.persistence.api.entity.AccountPolicy;
import org.apache.syncope.persistence.api.entity.ConnInstance;
+import org.apache.syncope.persistence.api.entity.ConnPoolConf;
import org.apache.syncope.persistence.api.entity.Entitlement;
import org.apache.syncope.persistence.api.entity.Entity;
import org.apache.syncope.persistence.api.entity.EntityFactory;
@@ -134,8 +135,8 @@ import org.springframework.stereotype.Component;
@Component
public class JPAEntityFactory implements EntityFactory {
- @Override
@SuppressWarnings("unchecked")
+ @Override
public <KEY, T extends Entity<KEY>> T newEntity(final Class<T> reference) {
T result;
@@ -258,6 +259,7 @@ public class JPAEntityFactory implements EntityFactory {
return result;
}
+ @SuppressWarnings("unchecked")
@Override
public <T extends Policy> T newPolicy(final Class<T> reference, final boolean global) {
T result;
@@ -277,4 +279,9 @@ public class JPAEntityFactory implements EntityFactory {
return result;
}
+ @Override
+ public ConnPoolConf newConnPoolConf() {
+ return new JPAConnPoolConf();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPushPolicy.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPushPolicy.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPushPolicy.java
index 1a661a9..b221330 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPushPolicy.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAPushPolicy.java
@@ -25,7 +25,7 @@ import org.apache.syncope.persistence.api.entity.PushPolicy;
@Entity
public class JPAPushPolicy extends JPAPolicy implements PushPolicy {
- private static final long serialVersionUID = -6090413855809521279L;
+ private static final long serialVersionUID = -5875589156893921113L;
public JPAPushPolicy() {
this(false);
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASecurityQuestion.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASecurityQuestion.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASecurityQuestion.java
index bfe76bc..4ce7d5e 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASecurityQuestion.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPASecurityQuestion.java
@@ -28,7 +28,7 @@ import org.apache.syncope.persistence.api.entity.user.SecurityQuestion;
@Table(name = JPASecurityQuestion.TABLE)
public class JPASecurityQuestion extends AbstractEntity<Long> implements SecurityQuestion {
- private static final long serialVersionUID = -7646140284033489392L;
+ private static final long serialVersionUID = 7675321820453579744L;
public static final String TABLE = "SecurityQuestion";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAttributableUtilFactory.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAttributableUtilFactory.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAttributableUtilFactory.java
new file mode 100644
index 0000000..6962b41
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/JPAttributableUtilFactory.java
@@ -0,0 +1,85 @@
+/*
+ * 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.persistence.jpa.entity;
+
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.persistence.api.entity.Attributable;
+import org.apache.syncope.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
+import org.apache.syncope.persistence.api.entity.conf.Conf;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.identityconnectors.framework.common.objects.ObjectClass;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JPAttributableUtilFactory implements AttributableUtilFactory {
+
+ @Override
+ public AttributableUtil getInstance(final AttributableType type) {
+ return new JPAAttributableUtil(type);
+ }
+
+ @Override
+ public AttributableUtil getInstance(final String attributableType) {
+ return new JPAAttributableUtil(AttributableType.valueOf(attributableType));
+ }
+
+ @Override
+ public AttributableUtil getInstance(final ObjectClass objectClass) {
+ AttributableType type = null;
+ if (ObjectClass.ACCOUNT.equals(objectClass)) {
+ type = AttributableType.USER;
+ }
+ if (ObjectClass.GROUP.equals(objectClass)) {
+ type = AttributableType.ROLE;
+ }
+
+ if (type == null) {
+ throw new IllegalArgumentException("ObjectClass not supported: " + objectClass);
+ }
+
+ return new JPAAttributableUtil(type);
+ }
+
+ @Override
+ public AttributableUtil getInstance(final Attributable<?, ?, ?> attributable) {
+ AttributableType type = null;
+ if (attributable instanceof User) {
+ type = AttributableType.USER;
+ }
+ if (attributable instanceof Role) {
+ type = AttributableType.ROLE;
+ }
+ if (attributable instanceof Membership) {
+ type = AttributableType.MEMBERSHIP;
+ }
+ if (attributable instanceof Conf) {
+ type = AttributableType.CONFIGURATION;
+ }
+
+ if (type == null) {
+ throw new IllegalArgumentException("Attributable type not supported: " + attributable.getClass().getName());
+ }
+
+ return new JPAAttributableUtil(type);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttr.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttr.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttr.java
index 74c7d66..3e0d404 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttr.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttr.java
@@ -48,7 +48,7 @@ import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttr;
@Table(name = JPACPlainAttr.TABLE)
public class JPACPlainAttr extends AbstractPlainAttr implements CPlainAttr {
- private static final long serialVersionUID = 6333601983691157406L;
+ private static final long serialVersionUID = 8022331942314540648L;
public static final String TABLE = "CPlainAttr";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
index 13e8e04..8cc830c 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrUniqueValue.java
@@ -35,7 +35,7 @@ import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttrValue;
@Table(name = JPACPlainAttrUniqueValue.TABLE)
public class JPACPlainAttrUniqueValue extends AbstractPlainAttrValue implements CPlainAttrUniqueValue {
- private static final long serialVersionUID = -64080804563305387L;
+ private static final long serialVersionUID = -2072445894710677162L;
public static final String TABLE = "CPlainAttrUniqueValue";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrValue.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrValue.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrValue.java
index 70e30f3..ff0a8ae 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrValue.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPACPlainAttrValue.java
@@ -35,7 +35,7 @@ import org.apache.syncope.persistence.jpa.entity.AbstractPlainAttrValue;
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class JPACPlainAttrValue extends AbstractPlainAttrValue implements CPlainAttrValue {
- private static final long serialVersionUID = -6259576015647897446L;
+ private static final long serialVersionUID = -4029895248193486171L;
public static final String TABLE = "CPlainAttrValue";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPAConf.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPAConf.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPAConf.java
index 3bfa884..0438543 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPAConf.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/conf/JPAConf.java
@@ -39,7 +39,7 @@ import org.apache.syncope.persistence.jpa.entity.AbstractAttributable;
@Cacheable
public class JPAConf extends AbstractAttributable<CPlainAttr, DerAttr, VirAttr> implements Conf {
- private static final long serialVersionUID = -5281258853142421875L;
+ private static final long serialVersionUID = 7671699609879382195L;
public static final String TABLE = "SyncopeConf";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttrTemplate.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttrTemplate.java
index 7ec7fcf..1b35470 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttrTemplate.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMDerAttrTemplate.java
@@ -32,7 +32,7 @@ import org.apache.syncope.persistence.jpa.entity.role.JPARole;
@Table(name = JPAMDerAttrTemplate.TABLE)
public class JPAMDerAttrTemplate extends AbstractAttrTemplate<MDerSchema> implements MDerAttrTemplate {
- private static final long serialVersionUID = -3424574558427502145L;
+ private static final long serialVersionUID = -4465930976210263434L;
public static final String TABLE = "MDerAttrTemplate";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrTemplate.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrTemplate.java
index fb8e728..ad6d2c2 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrTemplate.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMPlainAttrTemplate.java
@@ -32,7 +32,7 @@ import org.apache.syncope.persistence.jpa.entity.role.JPARole;
@Table(name = JPAMPlainAttrTemplate.TABLE)
public class JPAMPlainAttrTemplate extends AbstractAttrTemplate<MPlainSchema> implements MPlainAttrTemplate {
- private static final long serialVersionUID = -3424574558427502145L;
+ private static final long serialVersionUID = -8768086609963244514L;
public static final String TABLE = "MPlainAttrTemplate";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttrTemplate.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttrTemplate.java
index 7bd60db..6840686 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttrTemplate.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/membership/JPAMVirAttrTemplate.java
@@ -32,7 +32,7 @@ import org.apache.syncope.persistence.jpa.entity.role.JPARole;
@Table(name = JPAMVirAttrTemplate.TABLE)
public class JPAMVirAttrTemplate extends AbstractAttrTemplate<MVirSchema> implements MVirAttrTemplate {
- private static final long serialVersionUID = -3424574558427502145L;
+ private static final long serialVersionUID = 6618560912535667392L;
public static final String TABLE = "MVirAttrTemplate";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttrTemplate.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttrTemplate.java
index ba565a7..3b382bb 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttrTemplate.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARDerAttrTemplate.java
@@ -31,7 +31,7 @@ import org.apache.syncope.persistence.jpa.entity.AbstractAttrTemplate;
@Table(name = JPARDerAttrTemplate.TABLE)
public class JPARDerAttrTemplate extends AbstractAttrTemplate<RDerSchema> implements RDerAttrTemplate {
- private static final long serialVersionUID = -3424574558427502145L;
+ private static final long serialVersionUID = 624868884107016649L;
public static final String TABLE = "RDerAttrTemplate";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARPlainAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARPlainAttrTemplate.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARPlainAttrTemplate.java
index 90ac153..7d88bf7 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARPlainAttrTemplate.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARPlainAttrTemplate.java
@@ -31,7 +31,7 @@ import org.apache.syncope.persistence.jpa.entity.AbstractAttrTemplate;
@Table(name = JPARPlainAttrTemplate.TABLE)
public class JPARPlainAttrTemplate extends AbstractAttrTemplate<RPlainSchema> implements RPlainAttrTemplate {
- private static final long serialVersionUID = -3424574558427502145L;
+ private static final long serialVersionUID = 6943917051517266268L;
public static final String TABLE = "RPlainAttrTemplate";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARVirAttrTemplate.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARVirAttrTemplate.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARVirAttrTemplate.java
index a5e41bd..2228663 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARVirAttrTemplate.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARVirAttrTemplate.java
@@ -31,7 +31,7 @@ import org.apache.syncope.persistence.jpa.entity.AbstractAttrTemplate;
@Table(name = JPARVirAttrTemplate.TABLE)
public class JPARVirAttrTemplate extends AbstractAttrTemplate<RVirSchema> implements RVirAttrTemplate {
- private static final long serialVersionUID = -3424574558427502145L;
+ private static final long serialVersionUID = 4896495904794493479L;
public static final String TABLE = "RVirAttrTemplate";
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARole.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARole.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARole.java
index 05c9e9f..50bcf42 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARole.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/role/JPARole.java
@@ -156,7 +156,7 @@ public class JPARole extends AbstractSubject<RPlainAttr, RDerAttr, RVirAttr> imp
@Basic(optional = true)
@Min(0)
@Max(1)
- private Integer inheritAttrs;
+ private Integer inheritPlainAttrs;
@Basic(optional = true)
@Min(0)
@@ -213,7 +213,7 @@ public class JPARole extends AbstractSubject<RPlainAttr, RDerAttr, RVirAttr> imp
inheritOwner = getBooleanAsInteger(false);
inheritTemplates = getBooleanAsInteger(false);
- inheritAttrs = getBooleanAsInteger(false);
+ inheritPlainAttrs = getBooleanAsInteger(false);
inheritDerAttrs = getBooleanAsInteger(false);
inheritVirAttrs = getBooleanAsInteger(false);
inheritPasswordPolicy = getBooleanAsInteger(false);
@@ -423,13 +423,13 @@ public class JPARole extends AbstractSubject<RPlainAttr, RDerAttr, RVirAttr> imp
}
@Override
- public boolean isInheritAttrs() {
- return isBooleanAsInteger(inheritAttrs);
+ public boolean isInheritPlainAttrs() {
+ return isBooleanAsInteger(inheritPlainAttrs);
}
@Override
- public void setInheritAttrs(final boolean inheritAttrs) {
- this.inheritAttrs = getBooleanAsInteger(inheritAttrs);
+ public void setInheritPlainAttrs(final boolean inheritPlainAttrs) {
+ this.inheritPlainAttrs = getBooleanAsInteger(inheritPlainAttrs);
}
/**
@@ -441,10 +441,10 @@ public class JPARole extends AbstractSubject<RPlainAttr, RDerAttr, RVirAttr> imp
public List<? extends RPlainAttr> findLastInheritedAncestorPlainAttrs() {
final Map<JPARPlainSchema, RPlainAttr> result = new HashMap<>();
- if (!isInheritAttrs()) {
+ if (!isInheritPlainAttrs()) {
return plainAttrs;
}
- if (isInheritAttrs() && getParent() != null) {
+ if (isInheritPlainAttrs() && getParent() != null) {
final Map<PlainSchema, RPlainAttr> attrMap = getPlainAttrMap();
// Add inherit attributes
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPASchedTask.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPASchedTask.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPASchedTask.java
index 649664d..ef03fd7 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPASchedTask.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPASchedTask.java
@@ -30,7 +30,7 @@ import org.apache.syncope.persistence.jpa.validation.entity.SchedTaskCheck;
@SchedTaskCheck
public class JPASchedTask extends JPATask implements SchedTask {
- private static final long serialVersionUID = -4141057723006682562L;
+ private static final long serialVersionUID = 7596236684832602180L;
protected String cronExpression;
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPATaskUtil.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPATaskUtil.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPATaskUtil.java
new file mode 100644
index 0000000..3fae881
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPATaskUtil.java
@@ -0,0 +1,132 @@
+/*
+ * 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.persistence.jpa.entity.task;
+
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.NotificationTaskTO;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.to.SyncTaskTO;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.persistence.api.entity.task.NotificationTask;
+import org.apache.syncope.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.persistence.api.entity.task.PushTask;
+import org.apache.syncope.persistence.api.entity.task.SchedTask;
+import org.apache.syncope.persistence.api.entity.task.SyncTask;
+import org.apache.syncope.persistence.api.entity.task.Task;
+import org.apache.syncope.persistence.api.entity.task.TaskUtil;
+
+@SuppressWarnings("unchecked")
+public final class JPATaskUtil implements TaskUtil {
+
+ private final TaskType type;
+
+ protected JPATaskUtil(final TaskType type) {
+ this.type = type;
+ }
+
+ @Override
+ public TaskType getType() {
+ return type;
+ }
+
+ @Override
+ public <T extends Task> Class<T> taskClass() {
+ Class<T> result = null;
+
+ switch (type) {
+ case PROPAGATION:
+ result = (Class<T>) PropagationTask.class;
+ break;
+
+ case SCHEDULED:
+ result = (Class<T>) SchedTask.class;
+ break;
+
+ case SYNCHRONIZATION:
+ result = (Class<T>) SyncTask.class;
+ break;
+
+ case PUSH:
+ result = (Class<T>) PushTask.class;
+ break;
+
+ case NOTIFICATION:
+ result = (Class<T>) NotificationTask.class;
+ break;
+
+ default:
+ }
+
+ return result;
+ }
+
+ @Override
+ public <T extends Task> T newTask() {
+ final Class<T> taskClass = taskClass();
+ try {
+ return taskClass == null ? null : taskClass.newInstance();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Override
+ public <T extends AbstractTaskTO> Class<T> taskTOClass() {
+ Class<T> result = null;
+
+ switch (type) {
+ case PROPAGATION:
+ result = (Class<T>) PropagationTaskTO.class;
+ break;
+
+ case SCHEDULED:
+ result = (Class<T>) SchedTaskTO.class;
+ break;
+
+ case SYNCHRONIZATION:
+ result = (Class<T>) SyncTaskTO.class;
+ break;
+
+ case PUSH:
+ result = (Class<T>) PushTaskTO.class;
+ break;
+
+ case NOTIFICATION:
+ result = (Class<T>) NotificationTaskTO.class;
+ break;
+
+ default:
+ }
+
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T extends AbstractTaskTO> T newTaskTO() {
+ final Class<T> taskClass = taskTOClass();
+ try {
+ return taskClass == null ? null : taskClass.newInstance();
+ } catch (Exception e) {
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPATaskUtilFactory.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPATaskUtilFactory.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPATaskUtilFactory.java
new file mode 100644
index 0000000..62f5dab
--- /dev/null
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/task/JPATaskUtilFactory.java
@@ -0,0 +1,91 @@
+/*
+ * 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.persistence.jpa.entity.task;
+
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.NotificationTaskTO;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.to.SyncTaskTO;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.persistence.api.entity.task.NotificationTask;
+import org.apache.syncope.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.persistence.api.entity.task.PushTask;
+import org.apache.syncope.persistence.api.entity.task.SchedTask;
+import org.apache.syncope.persistence.api.entity.task.SyncTask;
+import org.apache.syncope.persistence.api.entity.task.Task;
+import org.apache.syncope.persistence.api.entity.task.TaskUtil;
+import org.apache.syncope.persistence.api.entity.task.TaskUtilFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class JPATaskUtilFactory implements TaskUtilFactory {
+
+ @Override
+ public TaskUtil getInstance(final TaskType type) {
+ return new JPATaskUtil(type);
+ }
+
+ @Override
+ public TaskUtil getInstance(final Task task) {
+ TaskType type;
+ if (task instanceof SyncTask) {
+ type = TaskType.SYNCHRONIZATION;
+ } else if (task instanceof PushTask) {
+ type = TaskType.PUSH;
+ } else if (task instanceof SchedTask) {
+ type = TaskType.SCHEDULED;
+ } else if (task instanceof PropagationTask) {
+ type = TaskType.PROPAGATION;
+ } else if (task instanceof NotificationTask) {
+ type = TaskType.NOTIFICATION;
+ } else {
+ throw new IllegalArgumentException("Invalid task: " + task);
+ }
+
+ return getInstance(type);
+ }
+
+ @Override
+ public TaskUtil getInstance(final Class<? extends AbstractTaskTO> taskClass) {
+ TaskType type;
+ if (taskClass == PropagationTaskTO.class) {
+ type = TaskType.PROPAGATION;
+ } else if (taskClass == NotificationTaskTO.class) {
+ type = TaskType.NOTIFICATION;
+ } else if (taskClass == SchedTaskTO.class) {
+ type = TaskType.SCHEDULED;
+ } else if (taskClass == SyncTaskTO.class) {
+ type = TaskType.SYNCHRONIZATION;
+ } else if (taskClass == PushTaskTO.class) {
+ type = TaskType.PUSH;
+ } else {
+ throw new IllegalArgumentException("Invalid TaskTO class: " + taskClass.getName());
+ }
+
+ return getInstance(type);
+ }
+
+ @Override
+ public TaskUtil getInstance(final AbstractTaskTO taskTO) {
+ return getInstance(taskTO.getClass());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUser.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUser.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUser.java
index ec28d6c..efc66ec 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUser.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/entity/user/JPAUser.java
@@ -62,9 +62,10 @@ import org.apache.syncope.persistence.api.entity.user.User;
import org.apache.syncope.persistence.jpa.validation.entity.UserCheck;
import org.apache.syncope.persistence.jpa.entity.AbstractSubject;
import org.apache.syncope.persistence.jpa.entity.JPAExternalResource;
+import org.apache.syncope.persistence.jpa.entity.JPASecurityQuestion;
import org.apache.syncope.persistence.jpa.entity.membership.JPAMembership;
import org.apache.syncope.server.security.Encryptor;
-import org.apache.syncope.server.security.SecureRandomUtil;
+import org.apache.syncope.server.utils.SecureRandomUtil;
/**
* Syncope user bean.
@@ -170,7 +171,7 @@ public class JPAUser extends AbstractSubject<UPlainAttr, UDerAttr, UVirAttr> imp
private Set<JPAExternalResource> resources;
@ManyToOne(fetch = FetchType.EAGER, optional = true)
- private SecurityQuestion securityQuestion;
+ private JPASecurityQuestion securityQuestion;
@Column(nullable = true)
private String securityAnswer;
@@ -520,7 +521,8 @@ public class JPAUser extends AbstractSubject<UPlainAttr, UDerAttr, UVirAttr> imp
@Override
public void setSecurityQuestion(final SecurityQuestion securityQuestion) {
- this.securityQuestion = securityQuestion;
+ checkType(securityQuestion, JPASecurityQuestion.class);
+ this.securityQuestion = (JPASecurityQuestion) securityQuestion;
}
@Override
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceValidator.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceValidator.java b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceValidator.java
index ba60ae4..c2bdb3a 100644
--- a/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceValidator.java
+++ b/syncope620/server/persistence-jpa/src/main/java/org/apache/syncope/persistence/jpa/validation/entity/ConnInstanceValidator.java
@@ -22,7 +22,7 @@ import javax.validation.ConstraintValidatorContext;
import org.apache.syncope.common.lib.types.EntityViolationType;
import org.apache.syncope.persistence.api.entity.ConnInstance;
import org.apache.syncope.persistence.jpa.entity.JPAConnPoolConf;
-import org.apache.syncope.server.utils.URIUtil;
+import org.apache.syncope.provisioning.api.URIUtil;
import org.apache.syncope.provisioning.api.ConnPoolConfUtil;
public class ConnInstanceValidator extends AbstractValidator<ConnInstanceCheck, ConnInstance> {
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/AbstractTest.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/AbstractTest.java b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/AbstractTest.java
index 2c78453..afb405a 100644
--- a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/AbstractTest.java
+++ b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/AbstractTest.java
@@ -18,6 +18,7 @@
*/
package org.apache.syncope.persistence.jpa;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
import org.apache.syncope.persistence.api.entity.EntityFactory;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -31,4 +32,7 @@ public abstract class AbstractTest {
@Autowired
protected EntityFactory entityFactory;
+ @Autowired
+ protected AttributableUtilFactory attrUtilFactory;
+
}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/AttrTest.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/AttrTest.java b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/AttrTest.java
index f751b77..0b5ccf1 100644
--- a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/AttrTest.java
+++ b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/AttrTest.java
@@ -87,15 +87,15 @@ public class AttrTest extends AbstractTest {
Exception thrown = null;
try {
- attribute.addValue("john.doe@gmail.com", JPAAttributableUtil.getInstance(AttributableType.USER));
- attribute.addValue("mario.rossi@gmail.com", JPAAttributableUtil.getInstance(AttributableType.USER));
+ attribute.addValue("john.doe@gmail.com", attrUtilFactory.getInstance(AttributableType.USER));
+ attribute.addValue("mario.rossi@gmail.com", attrUtilFactory.getInstance(AttributableType.USER));
} catch (ValidationException e) {
thrown = e;
}
assertNull("no validation exception expected here ", thrown);
try {
- attribute.addValue("http://www.apache.org", JPAAttributableUtil.getInstance(AttributableType.USER));
+ attribute.addValue("http://www.apache.org", attrUtilFactory.getInstance(AttributableType.USER));
} catch (ValidationException e) {
thrown = e;
}
@@ -119,13 +119,13 @@ public class AttrTest extends AbstractTest {
Exception thrown = null;
try {
- attribute.addValue("A", JPAAttributableUtil.getInstance(AttributableType.USER));
+ attribute.addValue("A", attrUtilFactory.getInstance(AttributableType.USER));
} catch (ValidationException e) {
thrown = e;
}
assertNotNull("validation exception expected here ", thrown);
- attribute.addValue("M", JPAAttributableUtil.getInstance(AttributableType.USER));
+ attribute.addValue("M", attrUtilFactory.getInstance(AttributableType.USER));
InvalidEntityException iee = null;
try {
@@ -183,7 +183,7 @@ public class AttrTest extends AbstractTest {
UPlainAttr attribute = entityFactory.newEntity(UPlainAttr.class);
attribute.setSchema(obscureSchema);
- attribute.addValue("testvalue", JPAAttributableUtil.getInstance(AttributableType.USER));
+ attribute.addValue("testvalue", attrUtilFactory.getInstance(AttributableType.USER));
attribute.setOwner(user);
user.addPlainAttr(attribute);
@@ -210,7 +210,7 @@ public class AttrTest extends AbstractTest {
UPlainAttr attribute = entityFactory.newEntity(UPlainAttr.class);
attribute.setSchema(photoSchema);
- attribute.addValue(photoB64Value, JPAAttributableUtil.getInstance(AttributableType.USER));
+ attribute.addValue(photoB64Value, attrUtilFactory.getInstance(AttributableType.USER));
attribute.setOwner(user);
user.addPlainAttr(attribute);
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/ConfTest.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/ConfTest.java b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/ConfTest.java
index ab662b7..143a4fe 100644
--- a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/ConfTest.java
+++ b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/ConfTest.java
@@ -72,7 +72,7 @@ public class ConfTest extends AbstractTest {
// 2. create conf
CPlainAttr newConf = entityFactory.newEntity(CPlainAttr.class);
newConf.setSchema(useless);
- newConf.addValue("2014-06-20", JPAAttributableUtil.getInstance(AttributableType.CONFIGURATION));
+ newConf.addValue("2014-06-20", attrUtilFactory.getInstance(AttributableType.CONFIGURATION));
confDAO.save(newConf);
CPlainAttr actual = confDAO.find("useless");
@@ -80,7 +80,7 @@ public class ConfTest extends AbstractTest {
// 3. update conf
newConf.getValues().clear();
- newConf.addValue("2014-06-20", JPAAttributableUtil.getInstance(AttributableType.CONFIGURATION));
+ newConf.addValue("2014-06-20", attrUtilFactory.getInstance(AttributableType.CONFIGURATION));
confDAO.save(newConf);
actual = confDAO.find("useless");
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/DerSchemaTest.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/DerSchemaTest.java b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/DerSchemaTest.java
index 19af5e9..94c61aa 100644
--- a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/DerSchemaTest.java
+++ b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/DerSchemaTest.java
@@ -73,7 +73,7 @@ public class DerSchemaTest extends AbstractTest {
UDerSchema cn = derSchemaDAO.find("cn", UDerSchema.class);
assertNotNull(cn);
- derSchemaDAO.delete(cn.getKey(), JPAAttributableUtil.getInstance(AttributableType.USER));
+ derSchemaDAO.delete(cn.getKey(), attrUtilFactory.getInstance(AttributableType.USER));
DerSchema actual = derSchemaDAO.find("cn", UDerSchema.class);
assertNull("delete did not work", actual);
@@ -82,7 +82,7 @@ public class DerSchemaTest extends AbstractTest {
RDerSchema rderiveddata = derSchemaDAO.find("rderiveddata", RDerSchema.class);
assertNotNull(rderiveddata);
- derSchemaDAO.delete(rderiveddata.getKey(), JPAAttributableUtil.getInstance(AttributableType.ROLE));
+ derSchemaDAO.delete(rderiveddata.getKey(), attrUtilFactory.getInstance(AttributableType.ROLE));
actual = derSchemaDAO.find("rderiveddata", RDerSchema.class);
assertNull("delete did not work", actual);
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/PlainSchemaTest.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/PlainSchemaTest.java b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/PlainSchemaTest.java
index 4e47087..652d32e 100644
--- a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/PlainSchemaTest.java
+++ b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/PlainSchemaTest.java
@@ -139,7 +139,7 @@ public class PlainSchemaTest extends AbstractTest {
public void delete() {
UPlainSchema fullnam = plainSchemaDAO.find("fullname", UPlainSchema.class);
- plainSchemaDAO.delete(fullnam.getKey(), JPAAttributableUtil.getInstance(AttributableType.USER));
+ plainSchemaDAO.delete(fullnam.getKey(), attrUtilFactory.getInstance(AttributableType.USER));
UPlainSchema actual = plainSchemaDAO.find("fullname", UPlainSchema.class);
assertNull("delete did not work", actual);
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/VirSchemaTest.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/VirSchemaTest.java b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/VirSchemaTest.java
index 9ae9e48..df60909 100644
--- a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/VirSchemaTest.java
+++ b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/entity/VirSchemaTest.java
@@ -72,7 +72,7 @@ public class VirSchemaTest extends AbstractTest {
public void delete() {
UVirSchema virtualdata = virSchemaDAO.find("virtualdata", UVirSchema.class);
- virSchemaDAO.delete(virtualdata.getKey(), JPAAttributableUtil.getInstance(AttributableType.USER));
+ virSchemaDAO.delete(virtualdata.getKey(), attrUtilFactory.getInstance(AttributableType.USER));
VirSchema actual = virSchemaDAO.find("virtualdata", UVirSchema.class);
assertNull("delete did not work", actual);
@@ -81,7 +81,7 @@ public class VirSchemaTest extends AbstractTest {
RVirSchema rvirtualdata = virSchemaDAO.find("rvirtualdata", RVirSchema.class);
assertNotNull(rvirtualdata);
- virSchemaDAO.delete(rvirtualdata.getKey(), JPAAttributableUtil.getInstance(AttributableType.ROLE));
+ virSchemaDAO.delete(rvirtualdata.getKey(), attrUtilFactory.getInstance(AttributableType.ROLE));
actual = virSchemaDAO.find("rvirtualdata", RVirSchema.class);
assertNull("delete did not work", actual);
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/AttrTest.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/AttrTest.java b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/AttrTest.java
index 1074726..a74e3a1 100644
--- a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/AttrTest.java
+++ b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/AttrTest.java
@@ -47,7 +47,6 @@ import org.apache.syncope.persistence.api.entity.user.UPlainAttr;
import org.apache.syncope.persistence.api.entity.user.UPlainAttrValue;
import org.apache.syncope.persistence.api.entity.user.User;
import org.apache.syncope.persistence.jpa.AbstractTest;
-import org.apache.syncope.persistence.jpa.entity.JPAAttributableUtil;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
@@ -125,7 +124,7 @@ public class AttrTest extends AbstractTest {
MPlainAttr attr = entityFactory.newEntity(MPlainAttr.class);
attr.setTemplate(template);
attr.setOwner(membership);
- attr.addValue("yellow", JPAAttributableUtil.getInstance(AttributableType.MEMBERSHIP));
+ attr.addValue("yellow", attrUtilFactory.getInstance(AttributableType.MEMBERSHIP));
membership.addPlainAttr(attr);
MPlainAttr actualAttribute = userDAO.save(user).getMembership(1L).getPlainAttr("color");
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/DerSchemaTest.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/DerSchemaTest.java b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/DerSchemaTest.java
index 685c2e2..2982423 100644
--- a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/DerSchemaTest.java
+++ b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/DerSchemaTest.java
@@ -27,7 +27,6 @@ import org.apache.syncope.persistence.api.dao.UserDAO;
import org.apache.syncope.persistence.api.entity.user.UDerAttr;
import org.apache.syncope.persistence.api.entity.user.UDerSchema;
import org.apache.syncope.persistence.jpa.AbstractTest;
-import org.apache.syncope.persistence.jpa.entity.JPAAttributableUtil;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
@@ -48,7 +47,7 @@ public class DerSchemaTest extends AbstractTest {
public void test() {
UDerSchema schema = derSchemaDAO.find("cn", UDerSchema.class);
- derSchemaDAO.delete(schema.getKey(), JPAAttributableUtil.getInstance(AttributableType.USER));
+ derSchemaDAO.delete(schema.getKey(), attrUtilFactory.getInstance(AttributableType.USER));
derSchemaDAO.flush();
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/PlainSchemaTest.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/PlainSchemaTest.java b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/PlainSchemaTest.java
index 29fb41e..710444c 100644
--- a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/PlainSchemaTest.java
+++ b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/PlainSchemaTest.java
@@ -36,7 +36,6 @@ import org.apache.syncope.persistence.api.entity.MappingItem;
import org.apache.syncope.persistence.api.entity.user.UPlainAttr;
import org.apache.syncope.persistence.api.entity.user.UPlainSchema;
import org.apache.syncope.persistence.jpa.AbstractTest;
-import org.apache.syncope.persistence.jpa.entity.JPAAttributableUtil;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
@@ -86,7 +85,7 @@ public class PlainSchemaTest extends AbstractTest {
assertFalse(mapItems.isEmpty());
// delete user schema fullname
- plainSchemaDAO.delete("fullname", JPAAttributableUtil.getInstance(AttributableType.USER));
+ plainSchemaDAO.delete("fullname", attrUtilFactory.getInstance(AttributableType.USER));
plainSchemaDAO.flush();
@@ -135,7 +134,7 @@ public class PlainSchemaTest extends AbstractTest {
assertFalse(mappings.isEmpty());
// delete user schema fullname
- plainSchemaDAO.delete("surname", JPAAttributableUtil.getInstance(AttributableType.USER));
+ plainSchemaDAO.delete("surname", attrUtilFactory.getInstance(AttributableType.USER));
plainSchemaDAO.flush();
@@ -148,7 +147,7 @@ public class PlainSchemaTest extends AbstractTest {
public void deleteALong() {
assertEquals(6, resourceDAO.find("resource-db-sync").getUmapping().getItems().size());
- plainSchemaDAO.delete("aLong", JPAAttributableUtil.getInstance(AttributableType.USER));
+ plainSchemaDAO.delete("aLong", attrUtilFactory.getInstance(AttributableType.USER));
assertNull(plainSchemaDAO.find("aLong", UPlainSchema.class));
plainSchemaDAO.flush();
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/SecurityQuestionTest.java
----------------------------------------------------------------------
diff --git a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/SecurityQuestionTest.java b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/SecurityQuestionTest.java
index 8fcac93..e4231b7 100644
--- a/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/SecurityQuestionTest.java
+++ b/syncope620/server/persistence-jpa/src/test/java/org/apache/syncope/persistence/jpa/relationship/SecurityQuestionTest.java
@@ -40,6 +40,8 @@ public class SecurityQuestionTest extends AbstractTest {
@Test
public void test() {
User user = userDAO.find(4L);
+ assertNull(user.getSecurityQuestion());
+ assertNull(user.getSecurityAnswer());
user.setSecurityQuestion(securityQuestionDAO.find(1L));
user.setSecurityAnswer("Rossi");
@@ -54,5 +56,6 @@ public class SecurityQuestionTest extends AbstractTest {
user = userDAO.find(4L);
assertNull(user.getSecurityQuestion());
+ assertNull(user.getSecurityAnswer());
}
}
[08/13] syncope git commit: [SYNCOPE-620] server logic in,
tests missing
Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UserLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UserLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UserLogic.java
new file mode 100644
index 0000000..870a075
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UserLogic.java
@@ -0,0 +1,534 @@
+/*
+ * 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.server.logic;
+
+import org.apache.syncope.server.security.UnauthorizedRoleException;
+import java.lang.reflect.Method;
+import java.security.AccessControlException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.mod.StatusMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.BulkActionResult.Status;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.persistence.api.RoleEntitlementUtil;
+import org.apache.syncope.persistence.api.dao.ConfDAO;
+import org.apache.syncope.persistence.api.dao.NotFoundException;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.dao.SubjectSearchDAO;
+import org.apache.syncope.persistence.api.dao.UserDAO;
+import org.apache.syncope.persistence.api.dao.search.OrderByClause;
+import org.apache.syncope.persistence.api.dao.search.SearchCond;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.provisioning.api.AttributableTransformer;
+import org.apache.syncope.provisioning.api.UserProvisioningManager;
+import org.apache.syncope.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.server.logic.data.UserDataBinder;
+import org.apache.syncope.server.security.AuthContextUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionInterceptor;
+
+/**
+ * Note that this controller does not extend {@link AbstractTransactionalLogic}, hence does not provide any
+ * Spring's Transactional logic at class level.
+ */
+@Component
+public class UserLogic extends AbstractSubjectLogic<UserTO, UserMod> {
+
+ @Autowired
+ protected UserDAO userDAO;
+
+ @Autowired
+ protected RoleDAO roleDAO;
+
+ @Autowired
+ protected SubjectSearchDAO searchDAO;
+
+ @Autowired
+ protected ConfDAO confDAO;
+
+ @Autowired
+ protected UserDataBinder binder;
+
+ @Autowired
+ protected PropagationManager propagationManager;
+
+ @Autowired
+ protected PropagationTaskExecutor taskExecutor;
+
+ @Autowired
+ protected AttributableTransformer attrTransformer;
+
+ @Autowired
+ protected UserProvisioningManager provisioningManager;
+
+ @Transactional(readOnly = true)
+ public boolean isSelfRegAllowed() {
+ return confDAO.find("selfRegistration.allowed", "false").getValues().get(0).getBooleanValue();
+ }
+
+ @Transactional(readOnly = true)
+ public boolean isPwdResetAllowed() {
+ return confDAO.find("passwordReset.allowed", "false").getValues().get(0).getBooleanValue();
+ }
+
+ @Transactional(readOnly = true)
+ public boolean isPwdResetRequiringSecurityQuestions() {
+ return confDAO.find("passwordReset.securityQuestion", "true").getValues().get(0).getBooleanValue();
+ }
+
+ @PreAuthorize("hasRole('USER_READ')")
+ public String getUsername(final Long key) {
+ return binder.getUserTO(key).getUsername();
+ }
+
+ @PreAuthorize("hasRole('USER_READ')")
+ public Long getKey(final String username) {
+ return binder.getUserTO(username).getKey();
+ }
+
+ @PreAuthorize("hasRole('USER_LIST')")
+ @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+ @Override
+ public int count() {
+ return userDAO.count(RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames()));
+ }
+
+ @PreAuthorize("hasRole('USER_LIST')")
+ @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+ @Override
+ public int searchCount(final SearchCond searchCondition) {
+ return searchDAO.count(RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames()),
+ searchCondition, SubjectType.USER);
+ }
+
+ @PreAuthorize("hasRole('USER_LIST')")
+ @Transactional(readOnly = true, rollbackFor = { Throwable.class })
+ @Override
+ public List<UserTO> list(final int page, final int size, final List<OrderByClause> orderBy) {
+ Set<Long> adminRoleIds = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
+
+ List<User> users = userDAO.findAll(adminRoleIds, page, size, orderBy);
+ List<UserTO> userTOs = new ArrayList<UserTO>(users.size());
+ for (User user : users) {
+ userTOs.add(binder.getUserTO(user));
+ }
+
+ return userTOs;
+ }
+
+ @PreAuthorize("isAuthenticated() "
+ + "and not(hasRole(T(org.apache.syncope.common.lib.SyncopeConstants).ANONYMOUS_ENTITLEMENT))")
+ @Transactional(readOnly = true)
+ public UserTO readSelf() {
+ return binder.getAuthenticatedUserTO();
+ }
+
+ @PreAuthorize("hasRole('USER_READ')")
+ @Transactional(readOnly = true)
+ @Override
+ public UserTO read(final Long key) {
+ return binder.getUserTO(key);
+ }
+
+ @PreAuthorize("hasRole('USER_LIST')")
+ @Transactional(readOnly = true)
+ @Override
+ public List<UserTO> search(final SearchCond searchCondition, final int page, final int size,
+ final List<OrderByClause> orderBy) {
+
+ final List<User> matchingUsers = searchDAO.search(
+ RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames()),
+ searchCondition, page, size, orderBy, SubjectType.USER);
+
+ final List<UserTO> result = new ArrayList<>(matchingUsers.size());
+ for (User user : matchingUsers) {
+ result.add(binder.getUserTO(user));
+ }
+
+ return result;
+ }
+
+ @PreAuthorize("isAnonymous() or hasRole(T(org.apache.syncope.common.lib.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")
+ public UserTO createSelf(final UserTO userTO, final boolean storePassword) {
+ return doCreate(userTO, storePassword);
+ }
+
+ @PreAuthorize("hasRole('USER_CREATE')")
+ public UserTO create(final UserTO userTO, final boolean storePassword) {
+ Set<Long> requestRoleIds = new HashSet<Long>(userTO.getMemberships().size());
+ for (MembershipTO membership : userTO.getMemberships()) {
+ requestRoleIds.add(membership.getRoleId());
+ }
+ Set<Long> adminRoleIds = RoleEntitlementUtil.getRoleKeys(AuthContextUtil.getOwnedEntitlementNames());
+ requestRoleIds.removeAll(adminRoleIds);
+ if (!requestRoleIds.isEmpty()) {
+ throw new UnauthorizedRoleException(requestRoleIds);
+ }
+
+ return doCreate(userTO, storePassword);
+ }
+
+ protected UserTO doCreate(final UserTO userTO, final boolean storePassword) {
+ // Attributable transformation (if configured)
+ UserTO actual = attrTransformer.transform(userTO);
+ LOG.debug("Transformed: {}", actual);
+
+ Map.Entry<Long, List<PropagationStatus>> created = provisioningManager.create(actual, storePassword);
+
+ final UserTO savedTO = binder.getUserTO(created.getKey());
+ savedTO.getPropagationStatusTOs().addAll(created.getValue());
+ return savedTO;
+ }
+
+ @PreAuthorize("isAuthenticated() "
+ + "and not(hasRole(T(org.apache.syncope.common.lib.SyncopeConstants).ANONYMOUS_ENTITLEMENT))")
+ public UserTO updateSelf(final UserMod userMod) {
+ UserTO userTO = binder.getAuthenticatedUserTO();
+
+ if (userTO.getKey() != userMod.getKey()) {
+ throw new AccessControlException("Not allowed for user with key " + userMod.getKey());
+ }
+
+ return update(userMod);
+ }
+
+ @PreAuthorize("hasRole('USER_UPDATE')")
+ @Override
+ public UserTO update(final UserMod userMod) {
+ // AttributableMod transformation (if configured)
+ UserMod actual = attrTransformer.transform(userMod);
+ LOG.debug("Transformed: {}", actual);
+
+ // SYNCOPE-501: check if there are memberships to be removed with virtual attributes assigned
+ boolean removeMemberships = false;
+ for (Long membershipId : actual.getMembershipsToRemove()) {
+ if (!binder.fillMembershipVirtual(
+ null,
+ null,
+ membershipId,
+ Collections.<String>emptySet(),
+ Collections.<AttrMod>emptySet(),
+ true).isEmpty()) {
+
+ removeMemberships = true;
+ }
+ }
+
+ Map.Entry<Long, List<PropagationStatus>> updated = provisioningManager.update(actual, removeMemberships);
+
+ final UserTO updatedTO = binder.getUserTO(updated.getKey());
+ updatedTO.getPropagationStatusTOs().addAll(updated.getValue());
+ return updatedTO;
+ }
+
+ protected Map.Entry<Long, List<PropagationStatus>> setStatusOnWfAdapter(final User user,
+ final StatusMod statusMod) {
+ Map.Entry<Long, List<PropagationStatus>> updated;
+
+ switch (statusMod.getType()) {
+ case SUSPEND:
+ updated = provisioningManager.suspend(user, statusMod);
+ break;
+
+ case REACTIVATE:
+ updated = provisioningManager.reactivate(user, statusMod);
+ break;
+
+ case ACTIVATE:
+ default:
+ updated = provisioningManager.activate(user, statusMod);
+ break;
+
+ }
+
+ return updated;
+ }
+
+ @PreAuthorize("hasRole('USER_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ public UserTO status(final StatusMod statusMod) {
+ User user = userDAO.authFecthUser(statusMod.getId());
+
+ Map.Entry<Long, List<PropagationStatus>> updated = setStatusOnWfAdapter(user, statusMod);
+ final UserTO savedTO = binder.getUserTO(updated.getKey());
+ savedTO.getPropagationStatusTOs().addAll(updated.getValue());
+ return savedTO;
+ }
+
+ @PreAuthorize("isAnonymous() or hasRole(T(org.apache.syncope.common.lib.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")
+ @Transactional
+ public void requestPasswordReset(final String username, final String securityAnswer) {
+ if (username == null) {
+ throw new NotFoundException("Null username");
+ }
+
+ User user = userDAO.find(username);
+ if (user == null) {
+ throw new NotFoundException("User " + username);
+ }
+
+ if (isPwdResetRequiringSecurityQuestions()
+ && (securityAnswer == null || !securityAnswer.equals(user.getSecurityAnswer()))) {
+
+ throw SyncopeClientException.build(ClientExceptionType.InvalidSecurityAnswer);
+ }
+
+ provisioningManager.requestPasswordReset(user.getKey());
+ }
+
+ @PreAuthorize("isAnonymous() or hasRole(T(org.apache.syncope.common.lib.SyncopeConstants).ANONYMOUS_ENTITLEMENT)")
+ @Transactional
+ public void confirmPasswordReset(final String token, final String password) {
+ User user = userDAO.findByToken(token);
+ if (user == null) {
+ throw new NotFoundException("User with token " + token);
+ }
+ provisioningManager.confirmPasswordReset(user, token, password);
+ }
+
+ @PreAuthorize("isAuthenticated() "
+ + "and not(hasRole(T(org.apache.syncope.common.lib.SyncopeConstants).ANONYMOUS_ENTITLEMENT))")
+ public UserTO deleteSelf() {
+ UserTO userTO = binder.getAuthenticatedUserTO();
+
+ return delete(userTO.getKey());
+ }
+
+ @PreAuthorize("hasRole('USER_DELETE')")
+ @Override
+ public UserTO delete(final Long key) {
+ List<Role> ownedRoles = roleDAO.findOwnedByUser(key);
+ if (!ownedRoles.isEmpty()) {
+ List<String> owned = new ArrayList<String>(ownedRoles.size());
+ for (Role role : ownedRoles) {
+ owned.add(role.getKey() + " " + role.getName());
+ }
+
+ SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.RoleOwnership);
+ sce.getElements().addAll(owned);
+ throw sce;
+ }
+
+ List<PropagationStatus> statuses = provisioningManager.delete(key);
+
+ final UserTO deletedTO;
+ User deleted = userDAO.find(key);
+ if (deleted == null) {
+ deletedTO = new UserTO();
+ deletedTO.setKey(key);
+ } else {
+ deletedTO = binder.getUserTO(key);
+ }
+ deletedTO.getPropagationStatusTOs().addAll(statuses);
+
+ return deletedTO;
+ }
+
+ @PreAuthorize("(hasRole('USER_DELETE') and #bulkAction.operation == #bulkAction.operation.DELETE) or "
+ + "(hasRole('USER_UPDATE') and "
+ + "(#bulkAction.operation == #bulkAction.operation.REACTIVATE or "
+ + "#bulkAction.operation == #bulkAction.operation.SUSPEND))")
+ public BulkActionResult bulk(final BulkAction bulkAction) {
+ BulkActionResult res = new BulkActionResult();
+
+ switch (bulkAction.getOperation()) {
+ case DELETE:
+ for (String key : bulkAction.getTargets()) {
+ try {
+ res.add(delete(Long.valueOf(key)).getKey(), Status.SUCCESS);
+ } catch (Exception e) {
+ LOG.error("Error performing delete for user {}", key, e);
+ res.add(key, Status.FAILURE);
+ }
+ }
+ break;
+
+ case SUSPEND:
+ for (String key : bulkAction.getTargets()) {
+ StatusMod statusMod = new StatusMod();
+ statusMod.setId(Long.valueOf(key));
+ statusMod.setType(StatusMod.ModType.SUSPEND);
+ try {
+ res.add(status(statusMod).getKey(), Status.SUCCESS);
+ } catch (Exception e) {
+ LOG.error("Error performing suspend for user {}", key, e);
+ res.add(key, Status.FAILURE);
+ }
+ }
+ break;
+
+ case REACTIVATE:
+ for (String key : bulkAction.getTargets()) {
+ StatusMod statusMod = new StatusMod();
+ statusMod.setId(Long.valueOf(key));
+ statusMod.setType(StatusMod.ModType.REACTIVATE);
+ try {
+ res.add(status(statusMod).getKey(), Status.SUCCESS);
+ } catch (Exception e) {
+ LOG.error("Error performing reactivate for user {}", key, e);
+ res.add(key, Status.FAILURE);
+ }
+ }
+ break;
+
+ default:
+ }
+
+ return res;
+ }
+
+ @PreAuthorize("hasRole('USER_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public UserTO unlink(final Long key, final Collection<String> resources) {
+ final UserMod userMod = new UserMod();
+ userMod.setKey(key);
+ userMod.getResourcesToRemove().addAll(resources);
+ Long updatedId = provisioningManager.unlink(userMod);
+
+ return binder.getUserTO(updatedId);
+ }
+
+ @PreAuthorize("hasRole('USER_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public UserTO link(final Long key, final Collection<String> resources) {
+ final UserMod userMod = new UserMod();
+ userMod.setKey(key);
+ userMod.getResourcesToAdd().addAll(resources);
+ return binder.getUserTO(provisioningManager.link(userMod));
+ }
+
+ @PreAuthorize("hasRole('USER_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public UserTO unassign(final Long key, final Collection<String> resources) {
+ final UserMod userMod = new UserMod();
+ userMod.setKey(key);
+ userMod.getResourcesToRemove().addAll(resources);
+ return update(userMod);
+ }
+
+ @PreAuthorize("hasRole('USER_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public UserTO assign(
+ final Long key,
+ final Collection<String> resources,
+ final boolean changepwd,
+ final String password) {
+
+ final UserMod userMod = new UserMod();
+ userMod.setKey(key);
+ userMod.getResourcesToAdd().addAll(resources);
+
+ if (changepwd) {
+ StatusMod statusMod = new StatusMod();
+ statusMod.setOnSyncope(false);
+ statusMod.getResourceNames().addAll(resources);
+ userMod.setPwdPropRequest(statusMod);
+ userMod.setPassword(password);
+ }
+
+ return update(userMod);
+ }
+
+ @PreAuthorize("hasRole('USER_UPDATE')")
+ @Transactional(rollbackFor = { Throwable.class })
+ @Override
+ public UserTO deprovision(final Long key, final Collection<String> resources) {
+ final User user = userDAO.authFecthUser(key);
+
+ List<PropagationStatus> statuses = provisioningManager.deprovision(key, resources);
+
+ final UserTO updatedUserTO = binder.getUserTO(user);
+ updatedUserTO.getPropagationStatusTOs().addAll(statuses);
+ return updatedUserTO;
+ }
+
+ @PreAuthorize("hasRole('USER_UPDATE')")
+ @Transactional(readOnly = true)
+ @Override
+ public UserTO provision(
+ final Long key,
+ final Collection<String> resources,
+ final boolean changePwd,
+ final String password) {
+
+ final UserTO original = binder.getUserTO(key);
+
+ //trick: assign and retrieve propagation statuses ...
+ original.getPropagationStatusTOs().addAll(
+ assign(key, resources, changePwd, password).getPropagationStatusTOs());
+
+ // .... rollback.
+ TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
+ return original;
+ }
+
+ @Override
+ protected UserTO resolveReference(final Method method, final Object... args) throws UnresolvedReferenceException {
+ Object id = null;
+
+ if (!"confirmPasswordReset".equals(method.getName()) && ArrayUtils.isNotEmpty(args)) {
+ for (int i = 0; id == null && i < args.length; i++) {
+ if (args[i] instanceof Long) {
+ id = (Long) args[i];
+ } else if (args[i] instanceof String) {
+ id = (String) args[i];
+ } else if (args[i] instanceof UserTO) {
+ id = ((UserTO) args[i]).getKey();
+ } else if (args[i] instanceof UserMod) {
+ id = ((UserMod) args[i]).getKey();
+ }
+ }
+ }
+
+ if ((id != null) && !id.equals(0l)) {
+ try {
+ return id instanceof Long ? binder.getUserTO((Long) id) : binder.getUserTO((String) id);
+ } catch (Throwable ignore) {
+ LOG.debug("Unresolved reference", ignore);
+ throw new UnresolvedReferenceException(ignore);
+ }
+ }
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UserWorkflowLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UserWorkflowLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UserWorkflowLogic.java
new file mode 100644
index 0000000..08b5e71
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/UserWorkflowLogic.java
@@ -0,0 +1,131 @@
+/*
+ * 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.server.logic;
+
+import java.lang.reflect.Method;
+import java.util.AbstractMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.syncope.common.lib.mod.AbstractAttributableMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.to.WorkflowFormTO;
+import org.apache.syncope.persistence.api.dao.UserDAO;
+import org.apache.syncope.persistence.api.entity.task.PropagationTask;
+import org.apache.syncope.persistence.api.entity.user.User;
+import org.apache.syncope.provisioning.api.propagation.PropagationManager;
+import org.apache.syncope.provisioning.api.propagation.PropagationTaskExecutor;
+import org.apache.syncope.server.logic.data.UserDataBinder;
+import org.apache.syncope.server.workflow.api.UserWorkflowAdapter;
+import org.apache.syncope.provisioning.api.WorkflowResult;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class UserWorkflowLogic extends AbstractTransactionalLogic<WorkflowFormTO> {
+
+ @Autowired
+ private UserWorkflowAdapter uwfAdapter;
+
+ @Autowired
+ private PropagationManager propagationManager;
+
+ @Autowired
+ private PropagationTaskExecutor taskExecutor;
+
+ @Autowired
+ private UserDataBinder binder;
+
+ @Autowired
+ private UserDAO userDAO;
+
+ @PreAuthorize("hasRole('WORKFLOW_FORM_CLAIM')")
+ @Transactional(rollbackFor = { Throwable.class })
+ public WorkflowFormTO claimForm(final String taskId) {
+ return uwfAdapter.claimForm(taskId);
+ }
+
+ @PreAuthorize("hasRole('USER_UPDATE')")
+ public UserTO executeWorkflowTask(final UserTO userTO, final String taskId) {
+ WorkflowResult<Long> updated = uwfAdapter.execute(userTO, taskId);
+
+ UserMod userMod = new UserMod();
+ userMod.setKey(userTO.getKey());
+
+ List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(
+ new WorkflowResult<Map.Entry<UserMod, Boolean>>(
+ new AbstractMap.SimpleEntry<UserMod, Boolean>(userMod, null),
+ updated.getPropByRes(), updated.getPerformedTasks()));
+
+ taskExecutor.execute(tasks);
+
+ return binder.getUserTO(updated.getResult());
+ }
+
+ @PreAuthorize("hasRole('WORKFLOW_FORM_READ') and hasRole('USER_READ')")
+ @Transactional(rollbackFor = { Throwable.class })
+ public WorkflowFormTO getFormForUser(final Long key) {
+ User user = userDAO.authFecthUser(key);
+ return uwfAdapter.getForm(user.getWorkflowId());
+ }
+
+ @PreAuthorize("hasRole('WORKFLOW_FORM_LIST')")
+ @Transactional(rollbackFor = { Throwable.class })
+ public List<WorkflowFormTO> getForms() {
+ return uwfAdapter.getForms();
+ }
+
+ @PreAuthorize("hasRole('WORKFLOW_FORM_READ') and hasRole('USER_READ')")
+ @Transactional(rollbackFor = { Throwable.class })
+ public List<WorkflowFormTO> getForms(final Long key, final String formName) {
+ User user = userDAO.authFecthUser(key);
+ return uwfAdapter.getForms(user.getWorkflowId(), formName);
+ }
+
+ @PreAuthorize("hasRole('WORKFLOW_FORM_SUBMIT')")
+ @Transactional(rollbackFor = { Throwable.class })
+ public UserTO submitForm(final WorkflowFormTO form) {
+ WorkflowResult<? extends AbstractAttributableMod> updated = uwfAdapter.submitForm(form);
+
+ // propByRes can be made empty by the workflow definition if no propagation should occur
+ // (for example, with rejected users)
+ if (updated.getResult() instanceof UserMod
+ && updated.getPropByRes() != null && !updated.getPropByRes().isEmpty()) {
+
+ List<PropagationTask> tasks = propagationManager.getUserUpdateTaskIds(
+ new WorkflowResult<Map.Entry<UserMod, Boolean>>(
+ new AbstractMap.SimpleEntry<UserMod, Boolean>((UserMod) updated.getResult(), Boolean.TRUE),
+ updated.getPropByRes(),
+ updated.getPerformedTasks()));
+
+ taskExecutor.execute(tasks);
+ }
+
+ return binder.getUserTO(updated.getResult().getKey());
+ }
+
+ @Override
+ protected WorkflowFormTO resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/WorkflowLogic.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/WorkflowLogic.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/WorkflowLogic.java
new file mode 100644
index 0000000..2e5ae74
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/WorkflowLogic.java
@@ -0,0 +1,115 @@
+/*
+ * 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.server.logic;
+
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import javax.ws.rs.core.MediaType;
+import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.syncope.server.workflow.api.RoleWorkflowAdapter;
+import org.apache.syncope.server.workflow.api.UserWorkflowAdapter;
+import org.apache.syncope.server.workflow.api.WorkflowAdapter;
+import org.apache.syncope.server.workflow.api.WorkflowDefinitionFormat;
+import org.apache.syncope.server.workflow.api.WorkflowException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+@Component
+public class WorkflowLogic extends AbstractTransactionalLogic<AbstractBaseBean> {
+
+ @Autowired
+ private UserWorkflowAdapter uwfAdapter;
+
+ @Autowired
+ private RoleWorkflowAdapter rwfAdapter;
+
+ private void exportDefinition(
+ final WorkflowAdapter adapter, final WorkflowDefinitionFormat format, final OutputStream os)
+ throws WorkflowException {
+
+ adapter.exportDefinition(format, os);
+ }
+
+ private WorkflowDefinitionFormat getFormat(final MediaType format) {
+ return format.equals(MediaType.APPLICATION_JSON_TYPE)
+ ? WorkflowDefinitionFormat.JSON
+ : WorkflowDefinitionFormat.XML;
+ }
+
+ @PreAuthorize("hasRole('WORKFLOW_DEF_READ')")
+ @Transactional(readOnly = true)
+ public void exportUserDefinition(final MediaType format, final OutputStream os)
+ throws WorkflowException {
+
+ exportDefinition(uwfAdapter, getFormat(format), os);
+ }
+
+ @PreAuthorize("hasRole('WORKFLOW_DEF_READ')")
+ @Transactional(readOnly = true)
+ public void exportRoleDefinition(final MediaType format, final OutputStream os)
+ throws WorkflowException {
+
+ exportDefinition(rwfAdapter, getFormat(format), os);
+ }
+
+ private void exportDiagram(final WorkflowAdapter adapter, final OutputStream os)
+ throws WorkflowException {
+ adapter.exportDiagram(os);
+ }
+
+ @PreAuthorize("hasRole('WORKFLOW_DEF_READ')")
+ @Transactional(readOnly = true)
+ public void exportUserDiagram(final OutputStream os)
+ throws WorkflowException {
+
+ exportDiagram(uwfAdapter, os);
+ }
+
+ @PreAuthorize("hasRole('WORKFLOW_DEF_READ')")
+ @Transactional(readOnly = true)
+ public void exportRoleDiagram(final OutputStream os)
+ throws WorkflowException {
+
+ exportDiagram(rwfAdapter, os);
+ }
+
+ private void importDefinition(
+ final WorkflowAdapter adapter, final WorkflowDefinitionFormat format, final String definition) {
+ adapter.importDefinition(format, definition);
+ }
+
+ @PreAuthorize("hasRole('WORKFLOW_DEF_UPDATE')")
+ public void importUserDefinition(final MediaType format, final String definition) {
+ importDefinition(uwfAdapter, getFormat(format), definition);
+ }
+
+ @PreAuthorize("hasRole('WORKFLOW_DEF_UPDATE')")
+ public void importRoleDefinition(final MediaType format, final String definition) {
+ importDefinition(rwfAdapter, getFormat(format), definition);
+ }
+
+ @Override
+ protected AbstractBaseBean resolveReference(final Method method, final Object... args)
+ throws UnresolvedReferenceException {
+
+ throw new UnresolvedReferenceException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/audit/AuditConnectionFactory.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/audit/AuditConnectionFactory.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/audit/AuditConnectionFactory.java
new file mode 100644
index 0000000..dae9fbf
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/audit/AuditConnectionFactory.java
@@ -0,0 +1,159 @@
+/*
+ * 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.server.logic.audit;
+
+import java.io.InputStream;
+import java.sql.Connection;
+import java.util.Properties;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.rmi.PortableRemoteObject;
+import javax.sql.DataSource;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathFactory;
+import org.apache.commons.dbcp2.BasicDataSource;
+import org.apache.commons.io.IOUtils;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PropertiesLoaderUtils;
+import org.springframework.jdbc.datasource.DataSourceUtils;
+import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
+import org.springframework.jdbc.datasource.init.ScriptUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.bootstrap.DOMImplementationRegistry;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSInput;
+import org.w3c.dom.ls.LSParser;
+
+/**
+ * LOG4J SQL connection factory that first attempts to obtain a {@link javax.sql.DataSource} from the JNDI name
+ * configured in Spring or, when not found, builds a new {@link javax.sql.DataSource DataSource} via Commons DBCP; if
+ * any datasource if found, the SQL init script is used to populate the database.
+ */
+public final class AuditConnectionFactory {
+
+ private static DataSource datasource;
+
+ private static final String PERSISTENCE_CONTEXT = "/persistenceContext.xml";
+
+ static {
+ // 1. Attempts to lookup for configured JNDI datasource (if present and available)
+ InputStream springConf = AuditConnectionFactory.class.getResourceAsStream(PERSISTENCE_CONTEXT);
+ String primary = null;
+ String fallback = null;
+ try {
+ DOMImplementationRegistry reg = DOMImplementationRegistry.newInstance();
+ DOMImplementationLS impl = (DOMImplementationLS) reg.getDOMImplementation("LS");
+ LSParser parser = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
+ LSInput lsinput = impl.createLSInput();
+ lsinput.setByteStream(springConf);
+ Document source = parser.parse(lsinput);
+
+ XPathFactory xPathfactory = XPathFactory.newInstance();
+ XPath xpath = xPathfactory.newXPath();
+
+ XPathExpression expr = xpath.compile("//*[local-name()='bean' and @id='persistenceProperties']/"
+ + "child::*[local-name()='property' and @name='primary']/@value");
+ primary = (String) expr.evaluate(source, XPathConstants.STRING);
+ expr = xpath.compile("//*[local-name()='bean' and @id='persistenceProperties']/"
+ + "child::*[local-name()='property' and @name='fallback']/@value");
+ fallback = (String) expr.evaluate(source, XPathConstants.STRING);
+
+ expr = xpath.compile("//*[local-name()='property' and @name='jndiName']/@value");
+ String jndiName = (String) expr.evaluate(source, XPathConstants.STRING);
+
+ Context ctx = new InitialContext();
+ Object obj = ctx.lookup(jndiName);
+
+ datasource = (DataSource) PortableRemoteObject.narrow(obj, DataSource.class);
+ } catch (Exception e) {
+ // ignore
+ } finally {
+ IOUtils.closeQuietly(springConf);
+ }
+
+ // 2. Creates Commons DBCP datasource
+ String initSQLScript = null;
+ try {
+ Resource persistenceProperties = null;
+ if (primary != null) {
+ if (primary.startsWith("file:")) {
+ persistenceProperties = new FileSystemResource(primary.substring(5));
+ }
+ if (primary.startsWith("classpath:")) {
+ persistenceProperties = new ClassPathResource(primary.substring(10));
+ }
+ }
+ if ((persistenceProperties == null || !persistenceProperties.exists()) && fallback != null) {
+ if (fallback.startsWith("file:")) {
+ persistenceProperties = new FileSystemResource(fallback.substring(5));
+ }
+ if (fallback.startsWith("classpath:")) {
+ persistenceProperties = new ClassPathResource(fallback.substring(10));
+ }
+ }
+ Properties persistence = PropertiesLoaderUtils.loadProperties(persistenceProperties);
+
+ initSQLScript = persistence.getProperty("audit.sql");
+
+ if (datasource == null) {
+ BasicDataSource bds = new BasicDataSource();
+ bds.setDriverClassName(persistence.getProperty("jpa.driverClassName"));
+ bds.setUrl(persistence.getProperty("jpa.url"));
+ bds.setUsername(persistence.getProperty("jpa.username"));
+ bds.setPassword(persistence.getProperty("jpa.password"));
+
+ bds.setLogAbandoned(true);
+ bds.setRemoveAbandonedOnBorrow(true);
+ bds.setRemoveAbandonedOnMaintenance(true);
+
+ datasource = bds;
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("Audit datasource configuration failed", e);
+ }
+
+ // 3. Initializes the chosen datasource
+ ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
+ populator.setScripts(new Resource[] { new ClassPathResource("/audit/" + initSQLScript) });
+ // forces no statement separation
+ populator.setSeparator(ScriptUtils.EOF_STATEMENT_SEPARATOR);
+ Connection conn = DataSourceUtils.getConnection(datasource);
+ try {
+ populator.populate(conn);
+ } finally {
+ DataSourceUtils.releaseConnection(conn, datasource);
+ }
+ }
+
+ public static Connection getConnection() {
+ if (datasource != null) {
+ return DataSourceUtils.getConnection(datasource);
+ }
+
+ throw new IllegalStateException("Audit dataSource init failed: check logs");
+ }
+
+ private AuditConnectionFactory() {
+ // empty constructor for static utility class
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/audit/AuditManager.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/audit/AuditManager.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/audit/AuditManager.java
new file mode 100644
index 0000000..ed674fd
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/audit/AuditManager.java
@@ -0,0 +1,107 @@
+/*
+ * 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.server.logic.audit;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.lib.types.AuditElements.Result;
+import org.apache.syncope.common.lib.types.AuditLoggerName;
+import org.apache.syncope.common.lib.types.LoggerLevel;
+import org.apache.syncope.persistence.api.dao.LoggerDAO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+public class AuditManager {
+
+ /**
+ * Logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(AuditManager.class);
+
+ @Autowired
+ private LoggerDAO loggerDAO;
+
+ public void audit(
+ final AuditElements.EventCategoryType type,
+ final String category,
+ final String subcategory,
+ final String event,
+ final Result result,
+ final Object before,
+ final Object output,
+ final Object... input) {
+
+ final Throwable throwable;
+ final StringBuilder message = new StringBuilder();
+
+ message.append("BEFORE:\n");
+ message.append("\t").append(before == null ? "unknown" : before).append("\n");
+
+ message.append("INPUT:\n");
+
+ if (ArrayUtils.isNotEmpty(input)) {
+ for (Object obj : input) {
+ message.append("\t").append(obj == null ? null : obj.toString()).append("\n");
+ }
+ } else {
+ message.append("\t").append("none").append("\n");
+ }
+
+ message.append("OUTPUT:\n");
+
+ if (output instanceof Throwable) {
+ throwable = (Throwable) output;
+ message.append("\t").append(throwable.getMessage());
+ } else {
+ throwable = null;
+ message.append("\t").append(output == null ? "none" : output.toString());
+ }
+
+ AuditLoggerName auditLoggerName = null;
+ try {
+ auditLoggerName = new AuditLoggerName(type, category, subcategory, event, result);
+ } catch (IllegalArgumentException e) {
+ LOG.error("Invalid audit parameters, aborting...", e);
+ }
+
+ if (auditLoggerName != null) {
+ org.apache.syncope.persistence.api.entity.Logger syncopeLogger =
+ loggerDAO.find(auditLoggerName.toLoggerName());
+ if (syncopeLogger != null && syncopeLogger.getLevel() == LoggerLevel.DEBUG) {
+ StringBuilder auditMessage = new StringBuilder();
+
+ final SecurityContext ctx = SecurityContextHolder.getContext();
+ if (ctx != null && ctx.getAuthentication() != null) {
+ auditMessage.append('[').append(ctx.getAuthentication().getName()).append(']').append(' ');
+ }
+ auditMessage.append(message);
+
+ final Logger logger = LoggerFactory.getLogger(auditLoggerName.toLoggerName());
+ if (throwable == null) {
+ logger.debug(auditMessage.toString());
+ } else {
+ logger.debug(auditMessage.toString(), throwable);
+ }
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/99369c31/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/AbstractAttributableDataBinder.java
----------------------------------------------------------------------
diff --git a/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/AbstractAttributableDataBinder.java b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/AbstractAttributableDataBinder.java
new file mode 100644
index 0000000..d84c62f
--- /dev/null
+++ b/syncope620/server/logic/src/main/java/org/apache/syncope/server/logic/data/AbstractAttributableDataBinder.java
@@ -0,0 +1,918 @@
+/*
+ * 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.server.logic.data;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeClientCompositeException;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.AbstractAttributableMod;
+import org.apache.syncope.common.lib.mod.AbstractSubjectMod;
+import org.apache.syncope.common.lib.mod.AttrMod;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.common.lib.types.MappingPurpose;
+import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
+import org.apache.syncope.persistence.api.dao.DerAttrDAO;
+import org.apache.syncope.persistence.api.dao.DerSchemaDAO;
+import org.apache.syncope.persistence.api.dao.ExternalResourceDAO;
+import org.apache.syncope.persistence.api.dao.MembershipDAO;
+import org.apache.syncope.persistence.api.dao.PlainAttrDAO;
+import org.apache.syncope.persistence.api.dao.PlainAttrValueDAO;
+import org.apache.syncope.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.persistence.api.dao.PolicyDAO;
+import org.apache.syncope.persistence.api.dao.RoleDAO;
+import org.apache.syncope.persistence.api.dao.UserDAO;
+import org.apache.syncope.persistence.api.dao.VirAttrDAO;
+import org.apache.syncope.persistence.api.dao.VirSchemaDAO;
+import org.apache.syncope.persistence.api.entity.Attributable;
+import org.apache.syncope.persistence.api.entity.AttributableUtil;
+import org.apache.syncope.persistence.api.entity.AttributableUtilFactory;
+import org.apache.syncope.persistence.api.entity.DerAttr;
+import org.apache.syncope.persistence.api.entity.DerSchema;
+import org.apache.syncope.persistence.api.entity.EntityFactory;
+import org.apache.syncope.persistence.api.entity.ExternalResource;
+import org.apache.syncope.persistence.api.entity.MappingItem;
+import org.apache.syncope.persistence.api.entity.PlainAttr;
+import org.apache.syncope.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.persistence.api.entity.PlainSchema;
+import org.apache.syncope.persistence.api.entity.Schema;
+import org.apache.syncope.persistence.api.entity.Subject;
+import org.apache.syncope.persistence.api.entity.VirAttr;
+import org.apache.syncope.persistence.api.entity.VirSchema;
+import org.apache.syncope.persistence.api.entity.membership.MDerAttr;
+import org.apache.syncope.persistence.api.entity.membership.MDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttr;
+import org.apache.syncope.persistence.api.entity.membership.MPlainAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.MVirAttr;
+import org.apache.syncope.persistence.api.entity.membership.MVirAttrTemplate;
+import org.apache.syncope.persistence.api.entity.membership.Membership;
+import org.apache.syncope.persistence.api.entity.role.RDerAttr;
+import org.apache.syncope.persistence.api.entity.role.RDerAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.RPlainAttr;
+import org.apache.syncope.persistence.api.entity.role.RPlainAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.RVirAttr;
+import org.apache.syncope.persistence.api.entity.role.RVirAttrTemplate;
+import org.apache.syncope.persistence.api.entity.role.Role;
+import org.apache.syncope.persistence.api.entity.user.UDerAttr;
+import org.apache.syncope.persistence.api.entity.user.UDerSchema;
+import org.apache.syncope.persistence.api.entity.user.UPlainAttr;
+import org.apache.syncope.persistence.api.entity.user.UPlainSchema;
+import org.apache.syncope.persistence.api.entity.user.UVirAttr;
+import org.apache.syncope.persistence.api.entity.user.UVirSchema;
+import org.apache.syncope.provisioning.api.propagation.PropagationByResource;
+import org.apache.syncope.server.utils.MappingUtil;
+import org.apache.syncope.server.utils.jexl.JexlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public abstract class AbstractAttributableDataBinder {
+
+ /**
+ * Logger.
+ */
+ protected static final Logger LOG = LoggerFactory.getLogger(AbstractAttributableDataBinder.class);
+
+ @Autowired
+ protected RoleDAO roleDAO;
+
+ @Autowired
+ protected PlainSchemaDAO plainSchemaDAO;
+
+ @Autowired
+ protected DerSchemaDAO derSchemaDAO;
+
+ @Autowired
+ protected VirSchemaDAO virSchemaDAO;
+
+ @Autowired
+ protected PlainAttrDAO plainAttrDAO;
+
+ @Autowired
+ protected DerAttrDAO derAttrDAO;
+
+ @Autowired
+ protected VirAttrDAO virAttrDAO;
+
+ @Autowired
+ protected PlainAttrValueDAO plainAttrValueDAO;
+
+ @Autowired
+ protected UserDAO userDAO;
+
+ @Autowired
+ protected ExternalResourceDAO resourceDAO;
+
+ @Autowired
+ protected MembershipDAO membershipDAO;
+
+ @Autowired
+ protected PolicyDAO policyDAO;
+
+ @Autowired
+ protected EntityFactory entityFactory;
+
+ @Autowired
+ protected AttributableUtilFactory attrUtilFactory;
+
+ @SuppressWarnings("unchecked")
+ protected <T extends Schema> T getSchema(final String schemaName, final Class<T> reference) {
+ T result = null;
+
+ if (PlainSchema.class.isAssignableFrom(reference)) {
+ result = (T) getPlainSchema(schemaName, (Class<? extends PlainSchema>) reference);
+ } else if (DerSchema.class.isAssignableFrom(reference)) {
+ result = (T) getDerSchema(schemaName, (Class<? extends DerSchema>) reference);
+ } else if (VirSchema.class.isAssignableFrom(reference)) {
+ result = (T) getVirSchema(schemaName, (Class<? extends VirSchema>) reference);
+ }
+
+ return result;
+ }
+
+ protected <T extends PlainSchema> T getPlainSchema(final String schemaName, final Class<T> reference) {
+ T schema = null;
+ if (StringUtils.isNotBlank(schemaName)) {
+ schema = plainSchemaDAO.find(schemaName, reference);
+
+ // safely ignore invalid schemas from AttrTO
+ // see http://code.google.com/p/syncope/issues/detail?id=17
+ if (schema == null) {
+ LOG.debug("Ignoring invalid schema {}", schemaName);
+ } else if (schema.isReadonly()) {
+ schema = null;
+
+ LOG.debug("Ignoring readonly schema {}", schemaName);
+ }
+ }
+
+ return schema;
+ }
+
+ private <T extends DerSchema> T getDerSchema(final String derSchemaName, final Class<T> reference) {
+ T derivedSchema = null;
+ if (StringUtils.isNotBlank(derSchemaName)) {
+ derivedSchema = derSchemaDAO.find(derSchemaName, reference);
+ if (derivedSchema == null) {
+ LOG.debug("Ignoring invalid derived schema {}", derSchemaName);
+ }
+ }
+
+ return derivedSchema;
+ }
+
+ private <T extends VirSchema> T getVirSchema(final String virSchemaName, final Class<T> reference) {
+ T virtualSchema = null;
+ if (StringUtils.isNotBlank(virSchemaName)) {
+ virtualSchema = virSchemaDAO.find(virSchemaName, reference);
+
+ if (virtualSchema == null) {
+ LOG.debug("Ignoring invalid virtual schema {}", virSchemaName);
+ }
+ }
+
+ return virtualSchema;
+ }
+
+ protected void fillAttribute(final List<String> values, final AttributableUtil attributableUtil,
+ final PlainSchema schema, final PlainAttr attr, final SyncopeClientException invalidValues) {
+
+ // if schema is multivalue, all values are considered for addition;
+ // otherwise only the fist one - if provided - is considered
+ List<String> valuesProvided = schema.isMultivalue()
+ ? values
+ : (values.isEmpty()
+ ? Collections.<String>emptyList()
+ : Collections.singletonList(values.iterator().next()));
+
+ for (String value : valuesProvided) {
+ if (value == null || value.isEmpty()) {
+ LOG.debug("Null value for {}, ignoring", schema.getKey());
+ } else {
+ try {
+ attr.addValue(value, attributableUtil);
+ } catch (InvalidPlainAttrValueException e) {
+ LOG.warn("Invalid value for attribute " + schema.getKey() + ": " + value, e);
+
+ invalidValues.getElements().add(schema.getKey() + ": " + value + " - " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ private boolean evaluateMandatoryCondition(final AttributableUtil attrUtil, final ExternalResource resource,
+ final Attributable attributable, final String intAttrName, final IntMappingType intMappingType) {
+
+ boolean result = false;
+
+ final List<MappingItem> mappings = MappingUtil.getMatchingMappingItems(
+ attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION), intAttrName, intMappingType);
+ for (Iterator<MappingItem> itor = mappings.iterator(); itor.hasNext() && !result;) {
+ final MappingItem mapping = itor.next();
+ result |= JexlUtil.evaluateMandatoryCondition(mapping.getMandatoryCondition(), attributable);
+ }
+
+ return result;
+ }
+
+ private boolean evaluateMandatoryCondition(final AttributableUtil attrUtil,
+ final Attributable<?, ?, ?> attributable, final String intAttrName, final IntMappingType intMappingType) {
+
+ boolean result = false;
+
+ if (attributable instanceof Subject) {
+ for (Iterator<? extends ExternalResource> itor = ((Subject<?, ?, ?>) attributable).getResources().iterator();
+ itor.hasNext() && !result;) {
+
+ final ExternalResource resource = itor.next();
+ if (resource.isEnforceMandatoryCondition()) {
+ result |= evaluateMandatoryCondition(attrUtil, resource, attributable, intAttrName, intMappingType);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private SyncopeClientException checkMandatory(final AttributableUtil attrUtil,
+ final Attributable<?, ?, ?> attributable) {
+
+ SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
+
+ // Check if there is some mandatory schema defined for which no value has been provided
+ List<? extends PlainSchema> plainSchemas;
+ switch (attrUtil.getType()) {
+ case ROLE:
+ plainSchemas = ((Role) attributable).getAttrTemplateSchemas(RPlainAttrTemplate.class);
+ break;
+
+ case MEMBERSHIP:
+ plainSchemas = ((Membership) attributable).getRole().getAttrTemplateSchemas(MPlainAttrTemplate.class);
+ break;
+
+ case USER:
+ default:
+ plainSchemas = plainSchemaDAO.findAll(attrUtil.plainSchemaClass());
+ }
+ for (PlainSchema schema : plainSchemas) {
+ if (attributable.getPlainAttr(schema.getKey()) == null
+ && !schema.isReadonly()
+ && (JexlUtil.evaluateMandatoryCondition(schema.getMandatoryCondition(), attributable)
+ || evaluateMandatoryCondition(attrUtil, attributable, schema.getKey(),
+ attrUtil.intMappingType()))) {
+
+ LOG.error("Mandatory schema " + schema.getKey() + " not provided with values");
+
+ reqValMissing.getElements().add(schema.getKey());
+ }
+ }
+
+ List<? extends DerSchema> derSchemas;
+ switch (attrUtil.getType()) {
+ case ROLE:
+ derSchemas = ((Role) attributable).getAttrTemplateSchemas(RDerAttrTemplate.class);
+ break;
+
+ case MEMBERSHIP:
+ derSchemas = ((Membership) attributable).getRole().getAttrTemplateSchemas(MDerAttrTemplate.class);
+ break;
+
+ case USER:
+ default:
+ derSchemas = derSchemaDAO.findAll(attrUtil.derSchemaClass());
+ }
+ for (DerSchema derSchema : derSchemas) {
+ if (attributable.getDerAttr(derSchema.getKey()) == null
+ && evaluateMandatoryCondition(attrUtil, attributable, derSchema.getKey(),
+ attrUtil.derIntMappingType())) {
+
+ LOG.error("Mandatory derived schema " + derSchema.getKey() + " does not evaluate to any value");
+
+ reqValMissing.getElements().add(derSchema.getKey());
+ }
+ }
+
+ List<? extends VirSchema> virSchemas;
+ switch (attrUtil.getType()) {
+ case ROLE:
+ virSchemas = ((Role) attributable).getAttrTemplateSchemas(RVirAttrTemplate.class);
+ break;
+
+ case MEMBERSHIP:
+ virSchemas = ((Membership) attributable).getRole().getAttrTemplateSchemas(MVirAttrTemplate.class);
+ break;
+
+ case USER:
+ default:
+ virSchemas = virSchemaDAO.findAll(attrUtil.virSchemaClass());
+ }
+ for (VirSchema virSchema : virSchemas) {
+ if (attributable.getVirAttr(virSchema.getKey()) == null
+ && !virSchema.isReadonly()
+ && evaluateMandatoryCondition(attrUtil, attributable, virSchema.getKey(),
+ attrUtil.virIntMappingType())) {
+
+ LOG.error("Mandatory virtual schema " + virSchema.getKey() + " not provided with values");
+
+ reqValMissing.getElements().add(virSchema.getKey());
+ }
+ }
+
+ return reqValMissing;
+ }
+
+ private void setPlainAttrSchema(final Attributable<?, ?, ?> attributable,
+ final PlainAttr attr, final PlainSchema schema) {
+
+ if (attr instanceof UPlainAttr) {
+ ((UPlainAttr) attr).setSchema((UPlainSchema) schema);
+ } else if (attr instanceof RPlainAttr) {
+ RPlainAttrTemplate template =
+ ((Role) attributable).getAttrTemplate(RPlainAttrTemplate.class, schema.getKey());
+ if (template != null) {
+ ((RPlainAttr) attr).setTemplate(template);
+ }
+ } else if (attr instanceof MPlainAttr) {
+ MPlainAttrTemplate template = ((Membership) attributable).getRole().
+ getAttrTemplate(MPlainAttrTemplate.class, schema.getKey());
+ if (template != null) {
+ ((MPlainAttr) attr).setTemplate(template);
+ }
+ }
+ }
+
+ private void setDerAttrSchema(final Attributable<?, ?, ?> attributable,
+ final DerAttr derAttr, final DerSchema derSchema) {
+
+ if (derAttr instanceof UDerAttr) {
+ ((UDerAttr) derAttr).setSchema((UDerSchema) derSchema);
+ } else if (derAttr instanceof RDerAttr) {
+ RDerAttrTemplate template = ((Role) attributable).
+ getAttrTemplate(RDerAttrTemplate.class, derSchema.getKey());
+ if (template != null) {
+ ((RDerAttr) derAttr).setTemplate(template);
+ }
+ } else if (derAttr instanceof MDerAttr) {
+ MDerAttrTemplate template = ((Membership) attributable).getRole().
+ getAttrTemplate(MDerAttrTemplate.class, derSchema.getKey());
+ if (template != null) {
+ ((MDerAttr) derAttr).setTemplate(template);
+ }
+ }
+ }
+
+ private void setVirAttrSchema(final Attributable<?, ?, ?> attributable,
+ final VirAttr virAttr, final VirSchema virSchema) {
+
+ if (virAttr instanceof UVirAttr) {
+ ((UVirAttr) virAttr).setSchema((UVirSchema) virSchema);
+ } else if (virAttr instanceof RVirAttr) {
+ RVirAttrTemplate template = ((Role) attributable).
+ getAttrTemplate(RVirAttrTemplate.class, virSchema.getKey());
+ if (template != null) {
+ ((RVirAttr) virAttr).setTemplate(template);
+ }
+ } else if (virAttr instanceof MVirAttr) {
+ MVirAttrTemplate template =
+ ((Membership) attributable).getRole().
+ getAttrTemplate(MVirAttrTemplate.class, virSchema.getKey());
+ if (template != null) {
+ ((MVirAttr) virAttr).setTemplate(template);
+ }
+ }
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public PropagationByResource fillVirtual(final Attributable attributable,
+ final Set<String> vAttrsToBeRemoved, final Set<AttrMod> vAttrsToBeUpdated,
+ final AttributableUtil attrUtil) {
+
+ PropagationByResource propByRes = new PropagationByResource();
+
+ final Set<ExternalResource> externalResources = new HashSet<>();
+ if (attributable instanceof Subject) {
+ externalResources.addAll(((Subject<?, ?, ?>) attributable).getResources());
+ }
+
+ if (attributable instanceof Membership) {
+ externalResources.clear();
+ externalResources.addAll(((Membership) attributable).getUser().getResources());
+ }
+
+ // 1. virtual attributes to be removed
+ for (String vAttrToBeRemoved : vAttrsToBeRemoved) {
+ VirSchema virSchema = getVirSchema(vAttrToBeRemoved, attrUtil.virSchemaClass());
+ if (virSchema != null) {
+ VirAttr virAttr = attributable.getVirAttr(virSchema.getKey());
+ if (virAttr == null) {
+ LOG.debug("No virtual attribute found for schema {}", virSchema.getKey());
+ } else {
+ attributable.removeVirAttr(virAttr);
+ virAttrDAO.delete(virAttr);
+ }
+
+ for (ExternalResource resource : resourceDAO.findAll()) {
+ for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+ if (virSchema.getKey().equals(mapItem.getIntAttrName())
+ && mapItem.getIntMappingType() == attrUtil.virIntMappingType()
+ && externalResources.contains(resource)) {
+
+ propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+
+ // Using virtual attribute as AccountId must be avoided
+ if (mapItem.isAccountid() && virAttr != null && !virAttr.getValues().isEmpty()) {
+ propByRes.addOldAccountId(resource.getKey(), virAttr.getValues().get(0));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ LOG.debug("Virtual attributes to be removed:\n{}", propByRes);
+
+ // 2. virtual attributes to be updated
+ for (AttrMod vAttrToBeUpdated : vAttrsToBeUpdated) {
+ VirSchema virSchema = getVirSchema(vAttrToBeUpdated.getSchema(), attrUtil.virSchemaClass());
+ VirAttr virAttr = null;
+ if (virSchema != null) {
+ virAttr = attributable.getVirAttr(virSchema.getKey());
+ if (virAttr == null) {
+ virAttr = attrUtil.newVirAttr();
+ setVirAttrSchema(attributable, virAttr, virSchema);
+ if (virAttr.getSchema() == null) {
+ LOG.debug("Ignoring {} because no valid schema or template was found", vAttrToBeUpdated);
+ } else {
+ attributable.addVirAttr(virAttr);
+ }
+ }
+ }
+
+ if (virSchema != null && virAttr != null && virAttr.getSchema() != null) {
+ for (ExternalResource resource : resourceDAO.findAll()) {
+ for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+ if (virSchema.getKey().equals(mapItem.getIntAttrName())
+ && mapItem.getIntMappingType() == attrUtil.virIntMappingType()
+ && externalResources.contains(resource)) {
+
+ propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+ }
+ }
+ }
+
+ final List<String> values = new ArrayList<>(virAttr.getValues());
+ values.removeAll(vAttrToBeUpdated.getValuesToBeRemoved());
+ values.addAll(vAttrToBeUpdated.getValuesToBeAdded());
+
+ virAttr.getValues().clear();
+ virAttr.getValues().addAll(values);
+
+ // Owner cannot be specified before otherwise a virtual attribute remove will be invalidated.
+ virAttr.setOwner(attributable);
+ }
+ }
+
+ LOG.debug("Virtual attributes to be added:\n{}", propByRes);
+
+ return propByRes;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected PropagationByResource fill(final Attributable attributable,
+ final AbstractAttributableMod attributableMod, final AttributableUtil attrUtil,
+ final SyncopeClientCompositeException scce) {
+
+ PropagationByResource propByRes = new PropagationByResource();
+
+ SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
+ if (attributable instanceof Subject && attributableMod instanceof AbstractSubjectMod) {
+ // 1. resources to be removed
+ for (String resourceToBeRemoved : ((AbstractSubjectMod) attributableMod).getResourcesToRemove()) {
+ ExternalResource resource = resourceDAO.find(resourceToBeRemoved);
+ if (resource != null) {
+ propByRes.add(ResourceOperation.DELETE, resource.getKey());
+ ((Subject<?, ?, ?>) attributable).removeResource(resource);
+ }
+ }
+
+ LOG.debug("Resources to be removed:\n{}", propByRes);
+
+ // 2. resources to be added
+ for (String resourceToBeAdded : ((AbstractSubjectMod) attributableMod).getResourcesToAdd()) {
+ ExternalResource resource = resourceDAO.find(resourceToBeAdded);
+ if (resource != null) {
+ propByRes.add(ResourceOperation.CREATE, resource.getKey());
+ ((Subject<?, ?, ?>) attributable).addResource(resource);
+ }
+ }
+
+ LOG.debug("Resources to be added:\n{}", propByRes);
+ }
+
+ // 3. attributes to be removed
+ for (String attributeToBeRemoved : attributableMod.getAttrsToRemove()) {
+ PlainSchema schema = getPlainSchema(attributeToBeRemoved, attrUtil.plainSchemaClass());
+ if (schema != null) {
+ PlainAttr attr = attributable.getPlainAttr(schema.getKey());
+ if (attr == null) {
+ LOG.debug("No attribute found for schema {}", schema);
+ } else {
+ String newValue = null;
+ for (AttrMod mod : attributableMod.getAttrsToUpdate()) {
+ if (schema.getKey().equals(mod.getSchema())) {
+ newValue = mod.getValuesToBeAdded().get(0);
+ }
+ }
+
+ if (!schema.isUniqueConstraint()
+ || (!attr.getUniqueValue().getStringValue().equals(newValue))) {
+
+ attributable.removePlainAttr(attr);
+ plainAttrDAO.delete(attr.getKey(), attrUtil.plainAttrClass());
+ }
+ }
+
+ if (attributable instanceof Subject) {
+ for (ExternalResource resource : resourceDAO.findAll()) {
+ for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+ if (schema.getKey().equals(mapItem.getIntAttrName())
+ && mapItem.getIntMappingType() == attrUtil.intMappingType()
+ && ((Subject<?, ?, ?>) attributable).getResources().contains(resource)) {
+
+ propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+
+ if (mapItem.isAccountid() && attr != null
+ && !attr.getValuesAsStrings().isEmpty()) {
+
+ propByRes.addOldAccountId(resource.getKey(),
+ attr.getValuesAsStrings().iterator().next());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ LOG.debug("Attributes to be removed:\n{}", propByRes);
+
+ // 4. attributes to be updated
+ for (AttrMod attributeMod : attributableMod.getAttrsToUpdate()) {
+ PlainSchema schema = getPlainSchema(attributeMod.getSchema(), attrUtil.plainSchemaClass());
+ PlainAttr attr = null;
+ if (schema != null) {
+ attr = attributable.getPlainAttr(schema.getKey());
+ if (attr == null) {
+ attr = attrUtil.newPlainAttr();
+ setPlainAttrSchema(attributable, attr, schema);
+ if (attr.getSchema() == null) {
+ LOG.debug("Ignoring {} because no valid schema or template was found", attributeMod);
+ } else {
+ attr.setOwner(attributable);
+ attributable.addPlainAttr(attr);
+ }
+ }
+ }
+
+ if (schema != null && attr != null && attr.getSchema() != null) {
+ if (attributable instanceof Subject) {
+ for (ExternalResource resource : resourceDAO.findAll()) {
+ for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+ if (schema.getKey().equals(mapItem.getIntAttrName())
+ && mapItem.getIntMappingType() == attrUtil.intMappingType()
+ && ((Subject<?, ?, ?>) attributable).getResources().contains(resource)) {
+
+ propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+ }
+ }
+ }
+ }
+
+ // 1.1 remove values
+ Set<Long> valuesToBeRemoved = new HashSet<>();
+ for (String valueToBeRemoved : attributeMod.getValuesToBeRemoved()) {
+ if (attr.getSchema().isUniqueConstraint()) {
+ if (attr.getUniqueValue() != null
+ && valueToBeRemoved.equals(attr.getUniqueValue().getValueAsString())) {
+
+ valuesToBeRemoved.add(attr.getUniqueValue().getKey());
+ }
+ } else {
+ for (PlainAttrValue mav : attr.getValues()) {
+ if (valueToBeRemoved.equals(mav.getValueAsString())) {
+ valuesToBeRemoved.add(mav.getKey());
+ }
+ }
+ }
+ }
+ for (Long attributeValueId : valuesToBeRemoved) {
+ plainAttrValueDAO.delete(attributeValueId, attrUtil.plainAttrValueClass());
+ }
+
+ // 1.2 add values
+ List<String> valuesToBeAdded = attributeMod.getValuesToBeAdded();
+ if (valuesToBeAdded != null && !valuesToBeAdded.isEmpty()
+ && (!schema.isUniqueConstraint() || attr.getUniqueValue() == null
+ || !valuesToBeAdded.iterator().next().equals(attr.getUniqueValue().getValueAsString()))) {
+
+ fillAttribute(attributeMod.getValuesToBeAdded(), attrUtil, schema, attr, invalidValues);
+ }
+
+ // if no values are in, the attribute can be safely removed
+ if (attr.getValuesAsStrings().isEmpty()) {
+ plainAttrDAO.delete(attr);
+ }
+ }
+ }
+
+ if (!invalidValues.isEmpty()) {
+ scce.addException(invalidValues);
+ }
+
+ LOG.debug("Attributes to be updated:\n{}", propByRes);
+
+ // 5. derived attributes to be removed
+ for (String derAttrToBeRemoved : attributableMod.getDerAttrsToRemove()) {
+ DerSchema derSchema = getDerSchema(derAttrToBeRemoved, attrUtil.derSchemaClass());
+ if (derSchema != null) {
+ DerAttr derAttr = attributable.getDerAttr(derSchema.getKey());
+ if (derAttr == null) {
+ LOG.debug("No derived attribute found for schema {}", derSchema.getKey());
+ } else {
+ derAttrDAO.delete(derAttr);
+ }
+
+ if (attributable instanceof Subject) {
+ for (ExternalResource resource : resourceDAO.findAll()) {
+ for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+ if (derSchema.getKey().equals(mapItem.getIntAttrName())
+ && mapItem.getIntMappingType() == attrUtil.derIntMappingType()
+ && ((Subject<?, ?, ?>) attributable).getResources().contains(resource)) {
+
+ propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+
+ if (mapItem.isAccountid() && derAttr != null
+ && !derAttr.getValue(attributable.getPlainAttrs()).isEmpty()) {
+
+ propByRes.addOldAccountId(resource.getKey(),
+ derAttr.getValue(attributable.getPlainAttrs()));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ LOG.debug("Derived attributes to be removed:\n{}", propByRes);
+
+ // 6. derived attributes to be added
+ for (String derAttrToBeAdded : attributableMod.getDerAttrsToAdd()) {
+ DerSchema derSchema = getDerSchema(derAttrToBeAdded, attrUtil.derSchemaClass());
+ if (derSchema != null) {
+ if (attributable instanceof Subject) {
+ for (ExternalResource resource : resourceDAO.findAll()) {
+ for (MappingItem mapItem : attrUtil.getMappingItems(resource, MappingPurpose.PROPAGATION)) {
+ if (derSchema.getKey().equals(mapItem.getIntAttrName())
+ && mapItem.getIntMappingType() == attrUtil.derIntMappingType()
+ && ((Subject<?, ?, ?>) attributable).getResources().contains(resource)) {
+
+ propByRes.add(ResourceOperation.UPDATE, resource.getKey());
+ }
+ }
+ }
+ }
+
+ DerAttr derAttr = attrUtil.newDerAttr();
+ setDerAttrSchema(attributable, derAttr, derSchema);
+ if (derAttr.getSchema() == null) {
+ LOG.debug("Ignoring {} because no valid schema or template was found", derAttrToBeAdded);
+ } else {
+ derAttr.setOwner(attributable);
+ attributable.addDerAttr(derAttr);
+ }
+ }
+ }
+
+ LOG.debug("Derived attributes to be added:\n{}", propByRes);
+
+ // 7. virtual attributes: for users and roles this is delegated to PropagationManager
+ if (AttributableType.USER != attrUtil.getType() && AttributableType.ROLE != attrUtil.getType()) {
+ fillVirtual(attributable, attributableMod.getVirAttrsToRemove(),
+ attributableMod.getVirAttrsToUpdate(), attrUtil);
+ }
+
+ // Finally, check if mandatory values are missing
+ SyncopeClientException requiredValuesMissing = checkMandatory(attrUtil, attributable);
+ if (!requiredValuesMissing.isEmpty()) {
+ scce.addException(requiredValuesMissing);
+ }
+
+ // Throw composite exception if there is at least one element set in the composing exceptions
+ if (scce.hasExceptions()) {
+ throw scce;
+ }
+
+ return propByRes;
+ }
+
+ /**
+ * Add virtual attributes and specify values to be propagated.
+ *
+ * @param attributable attributable.
+ * @param vAttrs virtual attributes to be added.
+ * @param attrUtil attributable util.
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void fillVirtual(final Attributable attributable, final Collection<AttrTO> vAttrs,
+ final AttributableUtil attrUtil) {
+
+ for (AttrTO attributeTO : vAttrs) {
+ VirAttr virAttr = attributable.getVirAttr(attributeTO.getSchema());
+ if (virAttr == null) {
+ VirSchema virSchema = getVirSchema(attributeTO.getSchema(), attrUtil.virSchemaClass());
+ if (virSchema != null) {
+ virAttr = attrUtil.newVirAttr();
+ setVirAttrSchema(attributable, virAttr, virSchema);
+ if (virAttr.getSchema() == null) {
+ LOG.debug("Ignoring {} because no valid schema or template was found", attributeTO);
+ } else {
+ virAttr.setOwner(attributable);
+ attributable.addVirAttr(virAttr);
+ virAttr.getValues().clear();
+ virAttr.getValues().addAll(attributeTO.getValues());
+ }
+ }
+ } else {
+ virAttr.getValues().clear();
+ virAttr.getValues().addAll(attributeTO.getValues());
+ }
+ }
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ protected void fill(final Attributable attributable, final AbstractAttributableTO attributableTO,
+ final AttributableUtil attributableUtil, final SyncopeClientCompositeException scce) {
+
+ // 1. attributes
+ SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
+ // Only consider attributeTO with values
+ for (AttrTO attributeTO : attributableTO.getPlainAttrs()) {
+ if (attributeTO.getValues() != null && !attributeTO.getValues().isEmpty()) {
+ PlainSchema schema = getPlainSchema(attributeTO.getSchema(), attributableUtil.plainSchemaClass());
+
+ if (schema != null) {
+ PlainAttr attr = attributable.getPlainAttr(schema.getKey());
+ if (attr == null) {
+ attr = attributableUtil.newPlainAttr();
+ setPlainAttrSchema(attributable, attr, schema);
+ }
+ if (attr.getSchema() == null) {
+ LOG.debug("Ignoring {} because no valid schema or template was found", attributeTO);
+ } else {
+ fillAttribute(attributeTO.getValues(), attributableUtil, schema, attr, invalidValues);
+
+ if (!attr.getValuesAsStrings().isEmpty()) {
+ attributable.addPlainAttr(attr);
+ attr.setOwner(attributable);
+ }
+ }
+ }
+ }
+ }
+
+ if (!invalidValues.isEmpty()) {
+ scce.addException(invalidValues);
+ }
+
+ // 2. derived attributes
+ for (AttrTO attributeTO : attributableTO.getDerAttrs()) {
+ DerSchema derSchema = getDerSchema(attributeTO.getSchema(), attributableUtil.derSchemaClass());
+
+ if (derSchema != null) {
+ DerAttr derAttr = attributableUtil.newDerAttr();
+ setDerAttrSchema(attributable, derAttr, derSchema);
+ if (derAttr.getSchema() == null) {
+ LOG.debug("Ignoring {} because no valid schema or template was found", attributeTO);
+ } else {
+ derAttr.setOwner(attributable);
+ attributable.addDerAttr(derAttr);
+ }
+ }
+ }
+
+ // 3. user and role virtual attributes will be evaluated by the propagation manager only (if needed).
+ if (AttributableType.USER == attributableUtil.getType()
+ || AttributableType.ROLE == attributableUtil.getType()) {
+
+ for (AttrTO vattrTO : attributableTO.getVirAttrs()) {
+ VirSchema virSchema = getVirSchema(vattrTO.getSchema(), attributableUtil.virSchemaClass());
+
+ if (virSchema != null) {
+ VirAttr virAttr = attributableUtil.newVirAttr();
+ setVirAttrSchema(attributable, virAttr, virSchema);
+ if (virAttr.getSchema() == null) {
+ LOG.debug("Ignoring {} because no valid schema or template was found", vattrTO);
+ } else {
+ virAttr.setOwner(attributable);
+ attributable.addVirAttr(virAttr);
+ }
+ }
+ }
+ }
+
+ fillVirtual(attributable, attributableTO.getVirAttrs(), attributableUtil);
+
+ // 4. resources
+ if (attributable instanceof Subject && attributableTO instanceof AbstractSubjectTO) {
+ for (String resourceName : ((AbstractSubjectTO) attributableTO).getResources()) {
+ ExternalResource resource = resourceDAO.find(resourceName);
+
+ if (resource != null) {
+ ((Subject<?, ?, ?>) attributable).addResource(resource);
+ }
+ }
+ }
+
+ SyncopeClientException requiredValuesMissing = checkMandatory(attributableUtil, attributable);
+ if (!requiredValuesMissing.isEmpty()) {
+ scce.addException(requiredValuesMissing);
+ }
+
+ // Throw composite exception if there is at least one element set in the composing exceptions
+ if (scce.hasExceptions()) {
+ throw scce;
+ }
+ }
+
+ protected void fillTO(final AbstractAttributableTO attributableTO,
+ final Collection<? extends PlainAttr> attrs,
+ final Collection<? extends DerAttr> derAttrs,
+ final Collection<? extends VirAttr> virAttrs,
+ final Collection<? extends ExternalResource> resources) {
+
+ AttrTO attributeTO;
+ for (PlainAttr attr : attrs) {
+ attributeTO = new AttrTO();
+ attributeTO.setSchema(attr.getSchema().getKey());
+ attributeTO.getValues().addAll(attr.getValuesAsStrings());
+ attributeTO.setReadonly(attr.getSchema().isReadonly());
+
+ attributableTO.getPlainAttrs().add(attributeTO);
+ }
+
+ for (DerAttr derAttr : derAttrs) {
+ attributeTO = new AttrTO();
+ attributeTO.setSchema(derAttr.getSchema().getKey());
+ attributeTO.getValues().add(derAttr.getValue(attrs));
+ attributeTO.setReadonly(true);
+
+ attributableTO.getDerAttrs().add(attributeTO);
+ }
+
+ for (VirAttr virAttr : virAttrs) {
+ attributeTO = new AttrTO();
+ attributeTO.setSchema(virAttr.getSchema().getKey());
+ attributeTO.getValues().addAll(virAttr.getValues());
+ attributeTO.setReadonly(virAttr.getSchema().isReadonly());
+
+ attributableTO.getVirAttrs().add(attributeTO);
+ }
+
+ if (attributableTO instanceof AbstractSubjectTO) {
+ for (ExternalResource resource : resources) {
+ ((AbstractSubjectTO) attributableTO).getResources().add(resource.getKey());
+ }
+ }
+ }
+}