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 2016/06/01 10:14:33 UTC

[1/6] syncope git commit: [SYNCOPE-846] removed flickering by providing two new behaviors [Forced Update!]

Repository: syncope
Updated Branches:
  refs/heads/SYNCOPE-862 f1adcc1e1 -> f0ef4df28 (forced update)
  refs/heads/master 12a8ef9b9 -> a7ef4e1fa (forced update)


[SYNCOPE-846] removed flickering by providing two new behaviors


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

Branch: refs/heads/SYNCOPE-862
Commit: 514cbf435f246f3271e3d4d2d0e8386b6c54ac5f
Parents: 07ca73d
Author: fmartelli <fa...@gmail.com>
Authored: Tue May 31 18:01:25 2016 +0200
Committer: fmartelli <fa...@gmail.com>
Committed: Tue May 31 18:01:25 2016 +0200

----------------------------------------------------------------------
 .../console/panels/AnyTypeClassesPanel.java     |  1 +
 .../client/console/panels/AnyTypesPanel.java    |  1 +
 .../syncope/client/console/panels/Realm.java    |  2 +-
 .../console/panels/RelationshipTypesPanel.java  |  1 +
 .../client/console/panels/SchemaTypePanel.java  |  2 +-
 .../form/IndicatorAutoCompleteBehavior.java     | 56 +++++++++++++++
 .../ajax/form/IndicatorModalCloseBehavior.java  | 62 ++++++++++++++++
 .../buttons/DefaultModalCloseButton.java        |  9 ++-
 .../markup/html/bootstrap/dialog/BaseModal.java | 75 +++++++++++++++++++-
 .../markup/html/form/AjaxTextFieldPanel.java    | 37 +++++++---
 10 files changed, 234 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/514cbf43/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
index 37d839a..46f84c3 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
@@ -80,6 +80,7 @@ public class AnyTypeClassesPanel extends TypesDirectoryPanel<AnyTypeClassTO, Any
                                 SyncopeConsoleSession.get().getService(AnyTypeClassService.class).update(modelObject);
                             }
                             SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                            AnyTypeClassesPanel.this.updateResultTable(target);
                             modal.close(target);
                         } catch (Exception e) {
                             LOG.error("While creating or updating AnyTypeClassTO", e);

http://git-wip-us.apache.org/repos/asf/syncope/blob/514cbf43/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
index 5333fe6..2238ad7 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
@@ -81,6 +81,7 @@ public class AnyTypesPanel extends TypesDirectoryPanel<AnyTypeTO, AnyTypeProvide
                                 SyncopeConsoleSession.get().getService(AnyTypeService.class).update(modelObject);
                             }
                             SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                            AnyTypesPanel.this.updateResultTable(target);
                             modal.close(target);
                         } catch (Exception e) {
                             LOG.error("While creating or updating {}", modelObject, e);

http://git-wip-us.apache.org/repos/asf/syncope/blob/514cbf43/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
index f058c5c..e09246c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
@@ -88,7 +88,7 @@ public abstract class Realm extends Panel {
                             public void onClick(final AjaxRequestTarget target, final RealmTO modelObject) {
                                 onClickTemplate(target);
                             }
-                        }, ActionLink.ActionType.TEMPLATE, StandardEntitlement.REALM_CREATE).
+                        }, ActionLink.ActionType.TEMPLATE, StandardEntitlement.REALM_UPDATE).
                         add(new ActionLink<RealmTO>(realmTO) {
 
                             private static final long serialVersionUID = 2802988981431379827L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/514cbf43/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypesPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypesPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypesPanel.java
index cd1de5e..a068e0f 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypesPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypesPanel.java
@@ -84,6 +84,7 @@ public class RelationshipTypesPanel extends TypesDirectoryPanel<RelationshipType
                                         getService(RelationshipTypeService.class).update(modelObject);
                             }
                             SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                            RelationshipTypesPanel.this.updateResultTable(target);
                             modal.close(target);
                         } catch (Exception e) {
                             LOG.error("While creating or updating {}", modelObject, e);

http://git-wip-us.apache.org/repos/asf/syncope/blob/514cbf43/client/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypePanel.java
index 5bba16c..c955b52 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypePanel.java
@@ -115,7 +115,7 @@ public class SchemaTypePanel extends TypesDirectoryPanel<AbstractSchemaTO, Schem
                                             SchemaService.class).update(schemaType, modelObject);
                                 }
 
-                                updateResultTable(target);
+                                SchemaTypePanel.this.updateResultTable(target);
                                 SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
                                 modal.close(target);
                             } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/514cbf43/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/IndicatorAutoCompleteBehavior.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/IndicatorAutoCompleteBehavior.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/IndicatorAutoCompleteBehavior.java
new file mode 100644
index 0000000..e33141b
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/IndicatorAutoCompleteBehavior.java
@@ -0,0 +1,56 @@
+/*
+ * 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.client.console.wicket.ajax.form;
+
+import java.io.Serializable;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.wicket.ajax.IAjaxIndicatorAware;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteBehavior;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.IAutoCompleteRenderer;
+
+/**
+ * An {@link AutoCompleteBehavior} not show in veil.
+ *
+ * @param <T> element type.
+ */
+public abstract class IndicatorAutoCompleteBehavior<T extends Serializable>
+        extends AutoCompleteBehavior<T> implements IAjaxIndicatorAware {
+
+    private static final long serialVersionUID = -5144403874783384604L;
+
+    private final String indicator;
+
+    public IndicatorAutoCompleteBehavior(final IAutoCompleteRenderer<T> renderer, final AutoCompleteSettings settings) {
+        this(renderer, settings, StringUtils.EMPTY);
+    }
+
+    public IndicatorAutoCompleteBehavior(
+            final IAutoCompleteRenderer<T> renderer,
+            final AutoCompleteSettings settings,
+            final String indicator) {
+        super(renderer, settings);
+        this.indicator = indicator;
+    }
+
+    @Override
+    public String getAjaxIndicatorMarkupId() {
+        return indicator;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/514cbf43/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/IndicatorModalCloseBehavior.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/IndicatorModalCloseBehavior.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/IndicatorModalCloseBehavior.java
new file mode 100644
index 0000000..a5da366
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/IndicatorModalCloseBehavior.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.client.console.wicket.ajax.form;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.ajax.IAjaxIndicatorAware;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+
+/**
+ * An {@link AjaxEventBehavior} not show in veil.
+ */
+public abstract class IndicatorModalCloseBehavior extends AjaxEventBehavior implements IAjaxIndicatorAware {
+
+    private static final long serialVersionUID = -5144403874783384604L;
+
+    private final String indicator;
+
+    /**
+     * Constructor.
+     */
+    public IndicatorModalCloseBehavior() {
+        this(StringUtils.EMPTY);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param indicator indicator.
+     */
+    public IndicatorModalCloseBehavior(final String indicator) {
+        super("hidden.bs.modal");
+        this.indicator = indicator;
+    }
+
+    @Override
+    protected void updateAjaxAttributes(final AjaxRequestAttributes attributes) {
+        super.updateAjaxAttributes(attributes);
+        attributes.setEventPropagation(AjaxRequestAttributes.EventPropagation.BUBBLE);
+    }
+
+    @Override
+    public String getAjaxIndicatorMarkupId() {
+        return indicator;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/514cbf43/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/buttons/DefaultModalCloseButton.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/buttons/DefaultModalCloseButton.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/buttons/DefaultModalCloseButton.java
index aa83b3e..2022801 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/buttons/DefaultModalCloseButton.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/buttons/DefaultModalCloseButton.java
@@ -19,10 +19,12 @@
 package org.apache.syncope.client.console.wicket.markup.html.bootstrap.buttons;
 
 import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.ModalCloseButton;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.wicket.ajax.IAjaxIndicatorAware;
 import org.apache.wicket.behavior.AttributeAppender;
 import org.apache.wicket.model.ResourceModel;
 
-public class DefaultModalCloseButton extends ModalCloseButton {
+public class DefaultModalCloseButton extends ModalCloseButton implements IAjaxIndicatorAware {
 
     private static final long serialVersionUID = -1097993976905448580L;
 
@@ -31,4 +33,9 @@ public class DefaultModalCloseButton extends ModalCloseButton {
         add(new AttributeAppender("class", " pull-left"));
         setOutputMarkupId(true);
     }
+
+    @Override
+    public String getAjaxIndicatorMarkupId() {
+        return StringUtils.EMPTY;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/514cbf43/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/dialog/BaseModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/dialog/BaseModal.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/dialog/BaseModal.java
index b28998f..e63d69a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/dialog/BaseModal.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/dialog/BaseModal.java
@@ -45,6 +45,10 @@ import org.apache.wicket.model.IModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.syncope.client.console.panels.SubmitableModalPanel;
+import org.apache.syncope.client.console.wicket.ajax.form.IndicatorModalCloseBehavior;
+import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
 
 public class BaseModal<T extends Serializable> extends Modal<T> {
 
@@ -73,6 +77,8 @@ public class BaseModal<T extends Serializable> extends Modal<T> {
 
     private final DefaultModalCloseButton defaultModalCloseButton;
 
+    private AjaxEventBehavior closeBehavior;
+
     public BaseModal(final String id) {
         super(id);
 
@@ -90,7 +96,7 @@ public class BaseModal<T extends Serializable> extends Modal<T> {
 
         form.add(content);
 
-        setUseCloseHandler(true);
+        useCloseHandler(true);
         this.windowClosedCallback = null;
         components = new ArrayList<>();
 
@@ -265,4 +271,71 @@ public class BaseModal<T extends Serializable> extends Modal<T> {
             return target;
         }
     }
+
+    //--------------------------------------------------------
+    // Reqired for SYNCOPE-846
+    //--------------------------------------------------------
+    /**
+     * Sets whether the close handler is used or not. Default is false.
+     *
+     * @param useCloseHandler True if close handler should be used
+     * @return This
+     */
+    public final Modal<T> useCloseHandler(final boolean useCloseHandler) {
+        if (useCloseHandler) {
+            if (closeBehavior == null) {
+                closeBehavior = new IndicatorModalCloseBehavior() {
+
+                    private static final long serialVersionUID = -4955472558917915340L;
+
+                    @Override
+                    protected void onEvent(final AjaxRequestTarget target) {
+                        if (isVisible()) {
+                            onClose(target);
+                            appendCloseDialogJavaScript(target);
+                        }
+                    }
+                };
+                add(closeBehavior);
+            }
+        } else if (closeBehavior != null) {
+            remove(closeBehavior);
+            closeBehavior = null;
+        }
+        return this;
+    }
+
+    @Override
+    public void renderHead(final IHeaderResponse response) {
+        super.renderHead(response);
+        response.render(OnDomReadyHeaderItem.forScript(createInitializerScript(getMarkupId(true))));
+    }
+
+    /**
+     * creates the initializer script of the modal dialog.
+     *
+     * @param markupId The component's markup id
+     * @return initializer script
+     */
+    private String createInitializerScript(final String markupId) {
+        return addCloseHandlerScript(markupId, createBasicInitializerScript(markupId));
+    }
+
+    /**
+     * adds close handler to initializer script, if use of close handler has been defined.
+     *
+     * @param markupId markup id
+     * @param script base script to prepend
+     * @return close handler script
+     */
+    private String addCloseHandlerScript(final String markupId, final String script) {
+        if (closeBehavior != null) {
+            return script + ";$('#" + markupId + "').on('hidden', function () { "
+                    + "  Wicket.Ajax.ajax({'u':'" + closeBehavior.getCallbackUrl() + "','c':'" + markupId + "'});"
+                    + "})";
+        }
+
+        return script;
+    }
+    //--------------------------------------------------------
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/514cbf43/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
index 5e4667a..4b85f66 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AjaxTextFieldPanel.java
@@ -26,10 +26,13 @@ import java.util.List;
 import java.util.regex.Pattern;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
+import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAutoCompleteBehavior;
 import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteBehavior;
 import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
 import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteTextField;
+import org.apache.wicket.extensions.ajax.markup.html.autocomplete.IAutoCompleteRenderer;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.ResourceModel;
 import org.apache.wicket.validation.IValidator;
@@ -63,17 +66,21 @@ public class AjaxTextFieldPanel extends FieldPanel<String> implements Cloneable
 
             @Override
             protected Iterator<String> getChoices(final String input) {
-                final Pattern pattern = Pattern.compile(".*" + Pattern.quote(input) + ".*", Pattern.CASE_INSENSITIVE);
+                return AjaxTextFieldPanel.this.getChoices(input);
+            }
 
-                final List<String> result = new ArrayList<>();
+            @Override
+            protected AutoCompleteBehavior<String> newAutoCompleteBehavior(
+                    final IAutoCompleteRenderer<String> renderer, final AutoCompleteSettings settings) {
+                return new IndicatorAutoCompleteBehavior<String>(renderer, settings) {
 
-                for (String choice : choices) {
-                    if (pattern.matcher(choice).matches()) {
-                        result.add(choice);
-                    }
-                }
+                    private static final long serialVersionUID = 1070808433195962931L;
 
-                return result.iterator();
+                    @Override
+                    protected Iterator<String> getChoices(final String input) {
+                        return AjaxTextFieldPanel.this.getChoices(input);
+                    }
+                };
             }
         };
         add(field.setLabel(new ResourceModel(name, name)).setOutputMarkupId(true));
@@ -106,6 +113,20 @@ public class AjaxTextFieldPanel extends FieldPanel<String> implements Cloneable
         return this;
     }
 
+    protected Iterator<String> getChoices(final String input) {
+        final Pattern pattern = Pattern.compile(".*" + Pattern.quote(input) + ".*", Pattern.CASE_INSENSITIVE);
+
+        final List<String> result = new ArrayList<>();
+
+        for (String choice : choices) {
+            if (pattern.matcher(choice).matches()) {
+                result.add(choice);
+            }
+        }
+
+        return result.iterator();
+    }
+
     @Override
     public FieldPanel<String> clone() {
         final AjaxTextFieldPanel panel = (AjaxTextFieldPanel) super.clone();


[4/6] syncope git commit: [SYNCOPE-862] Preliminary work

Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
index a144d67..0ccbe14 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AbstractAnyDataBinder.java
@@ -26,7 +26,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeClientCompositeException;
@@ -41,6 +40,7 @@ import org.apache.syncope.common.lib.to.RelationshipTO;
 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.PatchOperation;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidPlainAttrValueException;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
@@ -59,6 +59,7 @@ import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.common.lib.types.PropagationByResource;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.provisioning.java.utils.ConnObjectUtils;
 import org.apache.syncope.core.provisioning.java.MappingManagerImpl;
 import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
@@ -73,6 +74,7 @@ import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
 import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.Relationship;
@@ -88,6 +90,7 @@ import org.apache.syncope.core.provisioning.api.VirAttrHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 
 abstract class AbstractAnyDataBinder {
 
@@ -150,7 +153,7 @@ abstract class AbstractAnyDataBinder {
     protected DerAttrHandler derAttrHandler;
 
     @Autowired
-    protected VirAttrHandler virAttrHander;
+    protected VirAttrHandler virAttrHandler;
 
     @Autowired
     protected ConnObjectUtils connObjectUtils;
@@ -186,20 +189,12 @@ abstract class AbstractAnyDataBinder {
         return schema;
     }
 
-    private DerSchema getDerSchema(final String derSchemaName) {
-        DerSchema schema = null;
-        if (StringUtils.isNotBlank(derSchemaName)) {
-            schema = derSchemaDAO.find(derSchemaName);
-            if (schema == null) {
-                LOG.debug("Ignoring invalid derived schema {}", derSchemaName);
-            }
-        }
-
-        return schema;
-    }
-
-    private void fillAttr(final List<String> values, final AnyUtils anyUtils,
-            final PlainSchema schema, final PlainAttr<?> attr, final SyncopeClientException invalidValues) {
+    private void fillAttr(
+            final List<String> values,
+            final AnyUtils anyUtils,
+            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
@@ -210,7 +205,7 @@ abstract class AbstractAnyDataBinder {
                         : Collections.singletonList(values.iterator().next()));
 
         for (String value : valuesProvided) {
-            if (value == null || value.isEmpty()) {
+            if (StringUtils.isBlank(value)) {
                 LOG.debug("Null value for {}, ignoring", schema.getKey());
             } else {
                 try {
@@ -265,18 +260,37 @@ abstract class AbstractAnyDataBinder {
         return reqValMissing;
     }
 
+    private void checkMandatory(
+            final PlainSchema schema,
+            final PlainAttr<?> attr,
+            final Any<?> any,
+            final SyncopeClientException reqValMissing) {
+
+        if (attr == null
+                && !schema.isReadonly()
+                && JexlUtils.evaluateMandatoryCondition(schema.getMandatoryCondition(), any)) {
+
+            LOG.error("Mandatory schema " + schema.getKey() + " not provided with values");
+
+            reqValMissing.getElements().add(schema.getKey());
+        }
+    }
+
     private SyncopeClientException checkMandatory(final Any<?> any, final AnyUtils anyUtils) {
         SyncopeClientException reqValMissing = SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
 
         // Check if there is some mandatory schema defined for which no value has been provided
-        for (PlainSchema schema : anyUtils.getAllowedSchemas(any, PlainSchema.class)) {
-            if (any.getPlainAttr(schema.getKey()) == null
-                    && !schema.isReadonly()
-                    && JexlUtils.evaluateMandatoryCondition(schema.getMandatoryCondition(), any)) {
-
-                LOG.error("Mandatory schema " + schema.getKey() + " not provided with values");
-
-                reqValMissing.getElements().add(schema.getKey());
+        AllowedSchemas<PlainSchema> allowedPlainSchemas = anyUtils.getAllowedSchemas(any, PlainSchema.class);
+        for (PlainSchema schema : allowedPlainSchemas.getForSelf()) {
+            checkMandatory(schema, any.getPlainAttr(schema.getKey()), any, reqValMissing);
+        }
+        for (Map.Entry<Group, Set<PlainSchema>> entry : allowedPlainSchemas.getForMemberships().entrySet()) {
+            if (any instanceof GroupableRelatable) {
+                GroupableRelatable<?, ?, ?, ?, ?> groupable = GroupableRelatable.class.cast(any);
+                Membership<?> membership = groupable.getMembership(entry.getKey().getKey());
+                for (PlainSchema schema : entry.getValue()) {
+                    checkMandatory(schema, groupable.getPlainAttr(schema.getKey(), membership), any, reqValMissing);
+                }
             }
         }
 
@@ -284,28 +298,16 @@ abstract class AbstractAnyDataBinder {
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    private void processAttrPatch(final Any any, final AttrPatch patch, final PlainSchema schema,
-            final AnyUtils anyUtils, final Set<ExternalResource> resources, final PropagationByResource propByRes,
+    protected void processAttrPatch(
+            final Any any,
+            final AttrPatch patch,
+            final PlainSchema schema,
+            final PlainAttr<?> attr,
+            final AnyUtils anyUtils,
+            final Set<ExternalResource> resources,
+            final PropagationByResource propByRes,
             final SyncopeClientException invalidValues) {
 
-        PlainAttr<?> attr = any.getPlainAttr(schema.getKey());
-        if (attr == null) {
-            LOG.debug("No plain attribute found for schema {}", schema);
-
-            switch (patch.getOperation()) {
-                case ADD_REPLACE:
-                    attr = anyUtils.newPlainAttr();
-                    ((PlainAttr) attr).setOwner(any);
-                    attr.setSchema(schema);
-                    any.add(attr);
-                    break;
-
-                case DELETE:
-                default:
-                    return;
-            }
-        }
-
         switch (patch.getOperation()) {
             case ADD_REPLACE:
                 // 1.1 remove values
@@ -317,14 +319,8 @@ abstract class AbstractAnyDataBinder {
                         plainAttrValueDAO.delete(attr.getUniqueValue().getKey(), anyUtils.plainAttrUniqueValueClass());
                     }
                 } else {
-                    Collection<String> valuesToBeRemoved = CollectionUtils.collect(attr.getValues(),
-                            new Transformer<PlainAttrValue, String>() {
-
-                        @Override
-                        public String transform(final PlainAttrValue input) {
-                            return input.getKey();
-                        }
-                    });
+                    Collection<String> valuesToBeRemoved =
+                            CollectionUtils.collect(attr.getValues(), EntityUtils.keyTransformer());
                     for (String attrValueKey : valuesToBeRemoved) {
                         plainAttrValueDAO.delete(attrValueKey, anyUtils.plainAttrValueClass());
                     }
@@ -347,13 +343,14 @@ abstract class AbstractAnyDataBinder {
 
             case DELETE:
             default:
-                any.getPlainAttrs().remove(attr);
+                any.remove(attr);
                 plainAttrDAO.delete(attr.getKey(), anyUtils.plainAttrClass());
         }
 
         for (ExternalResource resource : resources) {
-            for (MappingItem mapItem : MappingManagerImpl.getPropagationMappingItems(resource.
-                    getProvision(any.getType()))) {
+            for (MappingItem mapItem
+                    : MappingManagerImpl.getPropagationMappingItems(resource.getProvision(any.getType()))) {
+
                 if (schema.getKey().equals(mapItem.getIntAttrName())
                         && mapItem.getIntMappingType() == anyUtils.plainIntMappingType()) {
 
@@ -367,7 +364,11 @@ abstract class AbstractAnyDataBinder {
         }
     }
 
-    protected PropagationByResource fill(final Any<?> any, final AnyPatch anyPatch, final AnyUtils anyUtils,
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected PropagationByResource fill(
+            final Any any,
+            final AnyPatch anyPatch,
+            final AnyUtils anyUtils,
             final SyncopeClientCompositeException scce) {
 
         PropagationByResource propByRes = new PropagationByResource();
@@ -421,7 +422,21 @@ abstract class AbstractAnyDataBinder {
                     LOG.debug("Invalid " + PlainSchema.class.getSimpleName()
                             + "{}, ignoring...", patch.getAttrTO().getSchema());
                 } else {
-                    processAttrPatch(any, patch, schema, anyUtils, resources, propByRes, invalidValues);
+                    PlainAttr<?> attr = any.getPlainAttr(schema.getKey());
+                    if (attr == null) {
+                        LOG.debug("No plain attribute found for schema {}", schema);
+
+                        if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
+                            attr = anyUtils.newPlainAttr();
+                            ((PlainAttr) attr).setOwner(any);
+                            attr.setSchema(schema);
+                            any.add(attr);
+
+                        }
+                    }
+                    if (attr != null) {
+                        processAttrPatch(any, patch, schema, attr, anyUtils, resources, propByRes, invalidValues);
+                    }
                 }
             }
         }
@@ -443,7 +458,10 @@ abstract class AbstractAnyDataBinder {
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
     protected void fill(
-            final Any any, final AnyTO anyTO, final AnyUtils anyUtils, final SyncopeClientCompositeException scce) {
+            final Any any,
+            final AnyTO anyTO,
+            final AnyUtils anyUtils,
+            final SyncopeClientCompositeException scce) {
 
         // 0. aux classes
         any.getAuxClasses().clear();
@@ -459,9 +477,9 @@ abstract class AbstractAnyDataBinder {
         // 1. attributes
         SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
 
-        // Only consider attributeTO with values
         for (AttrTO attrTO : anyTO.getPlainAttrs()) {
-            if (attrTO.getValues() != null && !attrTO.getValues().isEmpty()) {
+            // Only consider attributeTO with values
+            if (!attrTO.getValues().isEmpty()) {
                 PlainSchema schema = getPlainSchema(attrTO.getSchema());
                 if (schema != null) {
                     PlainAttr attr = any.getPlainAttr(schema.getKey());
@@ -506,6 +524,44 @@ abstract class AbstractAnyDataBinder {
         }
     }
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    protected void fill(
+            final Any any,
+            final Membership membership,
+            final MembershipTO membershipTO,
+            final AnyUtils anyUtils,
+            final SyncopeClientCompositeException scce) {
+
+        SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
+        for (AttrTO attrTO : membershipTO.getPlainAttrs()) {
+            if (!attrTO.getValues().isEmpty()) {
+                PlainSchema schema = getPlainSchema(attrTO.getSchema());
+                if (schema != null) {
+                    GroupablePlainAttr attr = GroupableRelatable.class.cast(any).
+                            getPlainAttr(schema.getKey(), membership);
+                    if (attr == null) {
+                        attr = anyUtils.newPlainAttr();
+                        attr.setOwner(any);
+                        attr.setMembership(membership);
+                        attr.setSchema(schema);
+                    }
+                    fillAttr(attrTO.getValues(), anyUtils, schema, attr, invalidValues);
+
+                    if (attr.getValuesAsStrings().isEmpty()) {
+                        attr.setOwner(null);
+                    } else {
+                        any.add(attr);
+                    }
+                }
+            }
+        }
+
+        if (!invalidValues.isEmpty()) {
+            scce.addException(invalidValues);
+        }
+    }
+
     protected void fillTO(final AnyTO anyTO,
             final String realmFullPath,
             final Collection<? extends AnyTypeClass> auxClasses,
@@ -519,30 +575,27 @@ abstract class AbstractAnyDataBinder {
         CollectionUtils.collect(auxClasses, EntityUtils.<AnyTypeClass>keyTransformer(), anyTO.getAuxClasses());
 
         for (PlainAttr<?> plainAttr : plainAttrs) {
-            AttrTO attrTO = new AttrTO();
-            attrTO.setSchema(plainAttr.getSchema().getKey());
-            attrTO.getValues().addAll(plainAttr.getValuesAsStrings());
-            attrTO.setReadonly(plainAttr.getSchema().isReadonly());
-
-            anyTO.getPlainAttrs().add(attrTO);
+            anyTO.getPlainAttrs().add(new AttrTO.Builder().
+                    schema(plainAttr.getSchema().getKey()).
+                    values(plainAttr.getValuesAsStrings()).
+                    readonly(plainAttr.getSchema().isReadonly()).
+                    build());
         }
 
         for (Map.Entry<DerSchema, String> entry : derAttrs.entrySet()) {
-            AttrTO attrTO = new AttrTO();
-            attrTO.setSchema(entry.getKey().getKey());
-            attrTO.getValues().add(entry.getValue());
-            attrTO.setReadonly(true);
-
-            anyTO.getDerAttrs().add(attrTO);
+            anyTO.getDerAttrs().add(new AttrTO.Builder().
+                    schema(entry.getKey().getKey()).
+                    value(entry.getValue()).
+                    readonly(true).
+                    build());
         }
 
         for (Map.Entry<VirSchema, List<String>> entry : virAttrs.entrySet()) {
-            AttrTO attrTO = new AttrTO();
-            attrTO.setSchema(entry.getKey().getKey());
-            attrTO.getValues().addAll(entry.getValue());
-            attrTO.setReadonly(entry.getKey().isReadonly());
-
-            anyTO.getVirAttrs().add(attrTO);
+            anyTO.getVirAttrs().add(new AttrTO.Builder().
+                    schema(entry.getKey().getKey()).
+                    values(entry.getValue()).
+                    readonly(entry.getKey().isReadonly()).
+                    build());
         }
 
         for (ExternalResource resource : resources) {
@@ -553,16 +606,45 @@ abstract class AbstractAnyDataBinder {
     protected RelationshipTO getRelationshipTO(final Relationship<? extends Any<?>, AnyObject> relationship) {
         return new RelationshipTO.Builder().
                 type(relationship.getType().getKey()).
-                left(relationship.getLeftEnd().getType().getKey(), relationship.getLeftEnd().getKey()).
                 right(relationship.getRightEnd().getType().getKey(), relationship.getRightEnd().getKey()).
                 build();
     }
 
-    protected MembershipTO getMembershipTO(final Membership<? extends Any<?>> membership) {
-        return new MembershipTO.Builder().
-                left(membership.getLeftEnd().getType().getKey(), membership.getLeftEnd().getKey()).
+    protected MembershipTO getMembershipTO(
+            final Collection<? extends PlainAttr<?>> plainAttrs,
+            final Map<DerSchema, String> derAttrs,
+            final Map<VirSchema, List<String>> virAttrs,
+            final Membership<? extends Any<?>> membership) {
+
+        MembershipTO membershipTO = new MembershipTO.Builder().
                 group(membership.getRightEnd().getKey(), membership.getRightEnd().getName()).
                 build();
+
+        for (PlainAttr<?> plainAttr : plainAttrs) {
+            membershipTO.getPlainAttrs().add(new AttrTO.Builder().
+                    schema(plainAttr.getSchema().getKey()).
+                    values(plainAttr.getValuesAsStrings()).
+                    readonly(plainAttr.getSchema().isReadonly()).
+                    build());
+        }
+
+        for (Map.Entry<DerSchema, String> entry : derAttrs.entrySet()) {
+            membershipTO.getDerAttrs().add(new AttrTO.Builder().
+                    schema(entry.getKey().getKey()).
+                    value(entry.getValue()).
+                    readonly(true).
+                    build());
+        }
+
+        for (Map.Entry<VirSchema, List<String>> entry : virAttrs.entrySet()) {
+            membershipTO.getVirAttrs().add(new AttrTO.Builder().
+                    schema(entry.getKey().getKey()).
+                    values(entry.getValue()).
+                    readonly(entry.getKey().isReadonly()).
+                    build());
+        }
+
+        return membershipTO;
     }
 
     protected Map<String, String> getConnObjectKeys(final Any<?> any) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
index 0e19eb7..d129dcb 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyObjectDataBinderImpl.java
@@ -29,7 +29,9 @@ import org.apache.commons.collections4.Transformer;
 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.SyncopeConstants;
 import org.apache.syncope.common.lib.patch.AnyObjectPatch;
+import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.MembershipPatch;
 import org.apache.syncope.common.lib.patch.RelationshipPatch;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
@@ -46,14 +48,17 @@ import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
-import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ARelationship;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.provisioning.api.data.AnyObjectDataBinder;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -74,7 +79,9 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
     @Transactional(readOnly = true)
     @Override
     public AnyObjectTO getAnyObjectTO(final String key) {
-        return getAnyObjectTO(anyObjectDAO.authFind(key), true);
+        return SyncopeConstants.UUID_PATTERN.matcher(key).matches()
+                ? getAnyObjectTO(anyObjectDAO.authFind(key), true)
+                : getAnyObjectTO(anyObjectDAO.authFindByName(key), true);
     }
 
     @Override
@@ -84,12 +91,15 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
 
         BeanUtils.copyProperties(anyObject, anyObjectTO, IGNORE_PROPERTIES);
 
-        Map<DerSchema, String> derAttrValues = derAttrHandler.getValues(anyObject);
         Map<VirSchema, List<String>> virAttrValues = details
-                ? virAttrHander.getValues(anyObject)
+                ? virAttrHandler.getValues(anyObject)
                 : Collections.<VirSchema, List<String>>emptyMap();
-        fillTO(anyObjectTO, anyObject.getRealm().getFullPath(), anyObject.getAuxClasses(),
-                anyObject.getPlainAttrs(), derAttrValues, virAttrValues, anyObjectDAO.findAllResources(anyObject));
+        fillTO(anyObjectTO, anyObject.getRealm().getFullPath(),
+                anyObject.getAuxClasses(),
+                anyObject.getPlainAttrs(),
+                derAttrHandler.getValues(anyObject),
+                virAttrValues,
+                anyObjectDAO.findAllResources(anyObject));
 
         if (details) {
             // relationships
@@ -107,7 +117,11 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
 
                 @Override
                 public MembershipTO transform(final AMembership membership) {
-                    return AnyObjectDataBinderImpl.this.getMembershipTO(membership);
+                    return getMembershipTO(
+                            anyObject.getPlainAttrs(membership),
+                            derAttrHandler.getValues(anyObject, membership),
+                            virAttrHandler.getValues(anyObject, membership),
+                            membership);
                 }
             }, anyObjectTO.getMemberships());
 
@@ -131,6 +145,16 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
 
         SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
 
+        // name
+        SyncopeClientException invalidGroups = SyncopeClientException.build(ClientExceptionType.InvalidGroup);
+        if (anyObjectTO.getName() == null) {
+            LOG.error("No name specified for this anyObject");
+
+            invalidGroups.getElements().add("No name specified for this anyObject");
+        } else {
+            anyObject.setName(anyObjectTO.getName());
+        }
+
         // realm
         Realm realm = realmDAO.findByFullPath(anyObjectTO.getRealm());
         if (realm == null) {
@@ -140,6 +164,7 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
         }
         anyObject.setRealm(realm);
 
+        AnyUtils anyUtils = anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT);
         if (anyObject.getRealm() != null) {
             AssignableCond assignableCond = new AssignableCond();
             assignableCond.setRealmFullPath(anyObject.getRealm().getFullPath());
@@ -199,6 +224,9 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
                     membership.setLeftEnd(anyObject);
 
                     anyObject.add(membership);
+
+                    // membership attributes
+                    fill(anyObject, membership, membershipTO, anyUtils, scce);
                 } else {
                     LOG.error("{} cannot be assigned to {}", group, anyObject);
 
@@ -210,8 +238,8 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
             }
         }
 
-        // attributes, derived attributes, virtual attributes and resources
-        fill(anyObject, anyObjectTO, anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT), scce);
+        // attributes and resources
+        fill(anyObject, anyObjectTO, anyUtils, scce);
 
         // Throw composite exception if there is at least one element set in the composing exceptions
         if (scce.hasExceptions()) {
@@ -233,8 +261,19 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
         // fetch connObjectKeys before update
         Map<String, String> oldConnObjectKeys = getConnObjectKeys(anyObject);
 
-        // attributes, derived attributes, virtual attributes and resources
-        propByRes.merge(fill(anyObject, anyObjectPatch, anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT), scce));
+        // realm
+        setRealm(anyObject, anyObjectPatch);
+
+        // name
+        if (anyObjectPatch.getName() != null && StringUtils.isNotBlank(anyObjectPatch.getName().getValue())) {
+            propByRes.addAll(ResourceOperation.UPDATE, anyObject.getResourceNames());
+
+            anyObject.setName(anyObjectPatch.getName().getValue());
+        }
+
+        AnyUtils anyUtils = anyUtilsFactory.getInstance(AnyTypeKind.ANY_OBJECT);
+        // attributes and resources
+        propByRes.merge(fill(anyObject, anyObjectPatch, anyUtils, scce));
 
         Set<String> toBeDeprovisioned = new HashSet<>();
         Set<String> toBeProvisioned = new HashSet<>();
@@ -253,6 +292,8 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
                             anyObject.getRelationship(relationshipType, patch.getRelationshipTO().getRightKey());
                     if (relationship != null) {
                         anyObject.getRelationships().remove(relationship);
+                        relationship.setLeftEnd(null);
+
                         toBeDeprovisioned.addAll(relationship.getRightEnd().getResourceNames());
                     }
 
@@ -293,22 +334,31 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
             }
         }
 
+        Set<ExternalResource> resources = anyUtils.getAllResources(anyObject);
+        SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
         // memberships
         List<Group> assignableGroups =
                 searchDAO.searchAssignable(anyObject.getRealm().getFullPath(), AnyTypeKind.GROUP);
 
-        for (MembershipPatch patch : anyObjectPatch.getMemberships()) {
-            if (patch.getMembershipTO() != null) {
-                AMembership membership = anyObject.getMembership(patch.getMembershipTO().getRightKey());
+        for (MembershipPatch membPatch : anyObjectPatch.getMemberships()) {
+            if (membPatch.getGroup() != null) {
+                AMembership membership = anyObject.getMembership(membPatch.getGroup());
                 if (membership != null) {
                     anyObject.getMemberships().remove(membership);
+                    membership.setLeftEnd(null);
+                    for (APlainAttr attr : anyObject.getPlainAttrs(membership)) {
+                        anyObject.remove(attr);
+                        attr.setOwner(null);
+                    }
+
                     toBeDeprovisioned.addAll(membership.getRightEnd().getResourceNames());
                 }
 
-                if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
-                    Group group = groupDAO.find(patch.getMembershipTO().getRightKey());
+                if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
+                    Group group = groupDAO.find(membPatch.getGroup());
                     if (group == null) {
-                        LOG.debug("Ignoring invalid group {}", patch.getMembershipTO().getRightKey());
+                        LOG.debug("Ignoring invalid group {}", membPatch.getGroup());
                     } else if (assignableGroups.contains(group)) {
                         membership = entityFactory.newEntity(AMembership.class);
                         membership.setRightEnd(group);
@@ -316,6 +366,37 @@ public class AnyObjectDataBinderImpl extends AbstractAnyDataBinder implements An
 
                         anyObject.add(membership);
 
+                        for (AttrPatch patch : membPatch.getPlainAttrs()) {
+                            if (patch.getAttrTO() != null) {
+                                PlainSchema schema = getPlainSchema(patch.getAttrTO().getSchema());
+                                if (schema == null) {
+                                    LOG.debug("Invalid " + PlainSchema.class.getSimpleName()
+                                            + "{}, ignoring...", patch.getAttrTO().getSchema());
+                                } else {
+                                    APlainAttr attr = anyObject.getPlainAttr(schema.getKey(), membership);
+                                    if (attr == null) {
+                                        LOG.debug("No plain attribute found for {} and membership of {}",
+                                                schema, membership.getRightEnd());
+
+                                        if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
+                                            attr = anyUtils.newPlainAttr();
+                                            attr.setOwner(anyObject);
+                                            attr.setMembership(membership);
+                                            attr.setSchema(schema);
+                                            anyObject.add(attr);
+
+                                            processAttrPatch(
+                                                    anyObject, patch, schema, attr, anyUtils,
+                                                    resources, propByRes, invalidValues);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        if (!invalidValues.isEmpty()) {
+                            scce.addException(invalidValues);
+                        }
+
                         toBeProvisioned.addAll(group.getResourceNames());
                     } else {
                         LOG.error("{} cannot be assigned to {}", group, anyObject);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
index 0aba4b9..38f1811 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GroupDataBinderImpl.java
@@ -110,7 +110,7 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
         }
         group.setRealm(realm);
 
-        // attributes, derived attributes, virtual attributes and resources
+        // attributes and resources
         fill(group, groupTO, anyUtilsFactory.getInstance(AnyTypeKind.GROUP), scce);
 
         // owner
@@ -211,7 +211,7 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
                     : groupDAO.find(groupPatch.getGroupOwner().getValue()));
         }
 
-        // attributes, derived attributes, virtual attributes and resources
+        // attributes and resources
         propByRes.merge(fill(group, groupPatch, anyUtilsFactory.getInstance(AnyTypeKind.GROUP), scce));
 
         // check if some connObjectKey was changed by the update above
@@ -325,7 +325,7 @@ public class GroupDataBinderImpl extends AbstractAnyDataBinder implements GroupD
 
         Map<DerSchema, String> derAttrValues = derAttrHandler.getValues(group);
         Map<VirSchema, List<String>> virAttrValues = details
-                ? virAttrHander.getValues(group)
+                ? virAttrHandler.getValues(group)
                 : Collections.<VirSchema, List<String>>emptyMap();
         fillTO(groupTO, group.getRealm().getFullPath(), group.getAuxClasses(),
                 group.getPlainAttrs(), derAttrValues, virAttrValues, group.getResources());

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
index 0a7f0a8..1581463 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java
@@ -34,6 +34,7 @@ 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.SyncopeConstants;
+import org.apache.syncope.common.lib.patch.AttrPatch;
 import org.apache.syncope.common.lib.patch.MembershipPatch;
 import org.apache.syncope.common.lib.patch.PasswordPatch;
 import org.apache.syncope.common.lib.patch.RelationshipPatch;
@@ -62,7 +63,8 @@ import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.dao.RoleDAO;
 import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
-import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.AnyUtils;
+import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.Role;
@@ -72,6 +74,7 @@ import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.user.URelationship;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
@@ -188,6 +191,7 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
         }
         user.setRealm(realm);
 
+        AnyUtils anyUtils = anyUtilsFactory.getInstance(AnyTypeKind.USER);
         if (user.getRealm() != null) {
             AssignableCond assignableCond = new AssignableCond();
             assignableCond.setRealmFullPath(user.getRealm().getFullPath());
@@ -237,6 +241,9 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
                     membership.setLeftEnd(user);
 
                     user.add(membership);
+
+                    // membership attributes
+                    fill(user, membership, membershipTO, anyUtils, scce);
                 } else {
                     LOG.error("{} cannot be assigned to {}", group, user);
 
@@ -248,8 +255,8 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             }
         }
 
-        // attributes, derived attributes, virtual attributes and resources
-        fill(user, userTO, anyUtilsFactory.getInstance(AnyTypeKind.USER), scce);
+        // attributes and resources
+        fill(user, userTO, anyUtils, scce);
 
         // set password
         if (StringUtils.isBlank(userTO.getPassword()) || !storePassword) {
@@ -371,8 +378,9 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             }
         }
 
-        // attributes, derived attributes, virtual attributes and resources
-        propByRes.merge(fill(user, userPatch, anyUtilsFactory.getInstance(AnyTypeKind.USER), scce));
+        AnyUtils anyUtils = anyUtilsFactory.getInstance(AnyTypeKind.USER);
+        // attributes and resources
+        propByRes.merge(fill(user, userPatch, anyUtils, scce));
 
         Set<String> toBeDeprovisioned = new HashSet<>();
         Set<String> toBeProvisioned = new HashSet<>();
@@ -391,6 +399,8 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
                             user.getRelationship(relationshipType, patch.getRelationshipTO().getRightKey());
                     if (relationship != null) {
                         user.getRelationships().remove(relationship);
+                        relationship.setLeftEnd(null);
+
                         toBeDeprovisioned.addAll(relationship.getRightEnd().getResourceNames());
                     }
 
@@ -420,22 +430,32 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             }
         }
 
+        Set<ExternalResource> resources = anyUtils.getAllResources(user);
+        SyncopeClientException invalidValues = SyncopeClientException.build(ClientExceptionType.InvalidValues);
+
         // memberships
         List<Group> assignableGroups =
                 searchDAO.searchAssignable(user.getRealm().getFullPath(), AnyTypeKind.GROUP);
 
-        for (MembershipPatch patch : userPatch.getMemberships()) {
-            if (patch.getMembershipTO() != null) {
-                UMembership membership = user.getMembership(patch.getMembershipTO().getRightKey());
+        for (MembershipPatch membPatch : userPatch.getMemberships()) {
+            if (membPatch.getGroup() != null) {
+                UMembership membership = user.getMembership(membPatch.getGroup());
                 if (membership != null) {
                     user.getMemberships().remove(membership);
+                    membership.setLeftEnd(null);
+                    for (UPlainAttr attr : user.getPlainAttrs(membership)) {
+                        user.remove(attr);
+                        attr.setOwner(null);
+                        attr.setMembership(null);
+                    }
+
                     toBeDeprovisioned.addAll(membership.getRightEnd().getResourceNames());
                 }
 
-                if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
-                    Group group = groupDAO.find(patch.getMembershipTO().getRightKey());
+                if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
+                    Group group = groupDAO.find(membPatch.getGroup());
                     if (group == null) {
-                        LOG.debug("Ignoring invalid group {}", patch.getMembershipTO().getRightKey());
+                        LOG.debug("Ignoring invalid group {}", membPatch.getGroup());
                     } else if (assignableGroups.contains(group)) {
                         membership = entityFactory.newEntity(UMembership.class);
                         membership.setRightEnd(group);
@@ -443,6 +463,37 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
 
                         user.add(membership);
 
+                        for (AttrPatch patch : membPatch.getPlainAttrs()) {
+                            if (patch.getAttrTO() != null) {
+                                PlainSchema schema = getPlainSchema(patch.getAttrTO().getSchema());
+                                if (schema == null) {
+                                    LOG.debug("Invalid " + PlainSchema.class.getSimpleName()
+                                            + "{}, ignoring...", patch.getAttrTO().getSchema());
+                                } else {
+                                    UPlainAttr attr = user.getPlainAttr(schema.getKey(), membership);
+                                    if (attr == null) {
+                                        LOG.debug("No plain attribute found for {} and membership of {}",
+                                                schema, membership.getRightEnd());
+
+                                        if (patch.getOperation() == PatchOperation.ADD_REPLACE) {
+                                            attr = anyUtils.newPlainAttr();
+                                            attr.setOwner(user);
+                                            attr.setMembership(membership);
+                                            attr.setSchema(schema);
+                                            user.add(attr);
+
+                                            processAttrPatch(
+                                                    user, patch, schema, attr, anyUtils,
+                                                    resources, propByRes, invalidValues);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        if (!invalidValues.isEmpty()) {
+                            scce.addException(invalidValues);
+                        }
+
                         toBeProvisioned.addAll(group.getResourceNames());
 
                         // SYNCOPE-686: if password is invertible and we are adding resources with password mapping,
@@ -509,12 +560,15 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
             userTO.setSecurityQuestion(user.getSecurityQuestion().getKey());
         }
 
-        Map<DerSchema, String> derAttrValues = derAttrHandler.getValues(user);
         Map<VirSchema, List<String>> virAttrValues = details
-                ? virAttrHander.getValues(user)
+                ? virAttrHandler.getValues(user)
                 : Collections.<VirSchema, List<String>>emptyMap();
-        fillTO(userTO, user.getRealm().getFullPath(), user.getAuxClasses(),
-                user.getPlainAttrs(), derAttrValues, virAttrValues, userDAO.findAllResources(user));
+        fillTO(userTO, user.getRealm().getFullPath(),
+                user.getAuxClasses(),
+                user.getPlainAttrs(),
+                derAttrHandler.getValues(user),
+                virAttrValues,
+                userDAO.findAllResources(user));
 
         if (details) {
             // roles
@@ -536,7 +590,11 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat
 
                 @Override
                 public MembershipTO transform(final UMembership membership) {
-                    return UserDataBinderImpl.this.getMembershipTO(membership);
+                    return getMembershipTO(
+                            user.getPlainAttrs(membership),
+                            derAttrHandler.getValues(user, membership),
+                            virAttrHandler.getValues(user, membership),
+                            membership);
                 }
             }, userTO.getMemberships());
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
index ead65e2..1b509d7 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SetUMembershipsJob.java
@@ -22,7 +22,6 @@ import java.util.Map;
 import java.util.Set;
 import org.apache.syncope.common.lib.patch.MembershipPatch;
 import org.apache.syncope.common.lib.patch.UserPatch;
-import org.apache.syncope.common.lib.to.MembershipTO;
 import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.core.provisioning.api.UserProvisioningManager;
 import org.apache.syncope.core.provisioning.api.job.JobManager;
@@ -70,7 +69,7 @@ public class SetUMembershipsJob extends AbstractInterruptableJob {
                             userPatch.getMemberships().add(
                                     new MembershipPatch.Builder().
                                     operation(PatchOperation.ADD_REPLACE).
-                                    membershipTO(new MembershipTO.Builder().group(groupKey).build()).
+                                    group(groupKey).
                                     build());
                         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
index 599aabf..995f483 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/pushpull/PullUtils.java
@@ -39,6 +39,7 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
@@ -237,6 +238,13 @@ public class PullUtils {
                 }
                 break;
 
+            case AnyObjectName:
+                AnyObject anyObject = anyObjectDAO.findByName(transfUid);
+                if (anyObject != null) {
+                    result.add(anyObject.getKey());
+                }
+                break;
+                
             default:
                 LOG.error("Invalid connObjectKey type '{}'", connObjectKeyItem.getIntMappingType());
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
index 124724f..af2631c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/utils/ConnObjectUtils.java
@@ -260,7 +260,7 @@ public class ConnObjectUtils {
                     }
                 }
 
-                connObjectTO.getPlainAttrs().add(attrTO);
+                connObjectTO.getAttrs().add(attrTO);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
index bbfa9ad..e7993ff 100644
--- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
+++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java
@@ -162,7 +162,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
         List<Task> tasks = engine.getTaskService().createTaskQuery().processInstanceId(user.getWorkflowId()).list();
         if (tasks.isEmpty() || tasks.size() > 1) {
-            LOG.warn("While checking if form task: unexpected task number ({})", tasks.size());
+            LOG.debug("While checking if form task: unexpected task number ({})", tasks.size());
         } else {
             try {
                 TaskFormData formData = engine.getFormService().getTaskFormData(tasks.get(0).getId());

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/build-tools/src/main/resources/testdb.sql
----------------------------------------------------------------------
diff --git a/fit/build-tools/src/main/resources/testdb.sql b/fit/build-tools/src/main/resources/testdb.sql
index df929da..610c8a3 100644
--- a/fit/build-tools/src/main/resources/testdb.sql
+++ b/fit/build-tools/src/main/resources/testdb.sql
@@ -45,5 +45,6 @@ lastModification TIMESTAMP);
 DROP TABLE testPRINTER IF EXISTS;
 CREATE TABLE testPRINTER (
 id CHAR(36) PRIMARY KEY,
+printername VARCHAR(80),
 location VARCHAR(80),
 lastModification TIMESTAMP);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java
index 40befd3..bfd04fe 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java
@@ -69,7 +69,7 @@ public class AnyObjectsITCase extends AbstractConsoleITCase {
                 "8559d14d-58c2-46eb-a2d4-a7d35161e8f8");
         assertNotNull(component);
 
-        wicketTester.clickLink(component.getPageRelativePath() + ":cells:3:cell:panelClone:cloneLink");
+        wicketTester.clickLink(component.getPageRelativePath() + ":cells:4:cell:panelClone:cloneLink");
 
         FormTester formTester = wicketTester.newFormTester(tabPanel + "outerObjectsRepeater:0:outer:form:content:form");
         assertNotNull(formTester);
@@ -87,7 +87,7 @@ public class AnyObjectsITCase extends AbstractConsoleITCase {
                 "8559d14d-58c2-46eb-a2d4-a7d35161e8f8");
         assertNotNull(component);
 
-        wicketTester.clickLink(component.getPageRelativePath() + ":cells:3:cell:panelEdit:editLink");
+        wicketTester.clickLink(component.getPageRelativePath() + ":cells:4:cell:panelEdit:editLink");
 
         wicketTester.assertComponent(tabPanel + "outerObjectsRepeater:0:outer:form:content:form:view:status:"
                 + "resources:firstLevelContainer:first:container:content:group:beans:0:fields:0", ListItem.class);
@@ -138,7 +138,7 @@ public class AnyObjectsITCase extends AbstractConsoleITCase {
                 "8559d14d-58c2-46eb-a2d4-a7d35161e8f8");
         assertNotNull(component);
 
-        wicketTester.assertComponent(component.getPageRelativePath() + ":cells:3:cell:panelDelete:deleteLink",
+        wicketTester.assertComponent(component.getPageRelativePath() + ":cells:4:cell:panelDelete:deleteLink",
                 IndicatingOnConfirmAjaxLink.class);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java
index 2407a15..cf82980 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BulkActionITCase.java
@@ -236,7 +236,7 @@ public class BulkActionITCase extends AbstractConsoleITCase {
         assertNotNull(component);
 
         wicketTester.clickLink(component.getPageRelativePath()
-                + ":cells:3:cell:panelManageResources:manageResourcesLink");
+                + ":cells:4:cell:panelManageResources:manageResourcesLink");
 
         wicketTester.assertComponent(tabPanel + "outerObjectsRepeater:1:outer:form:content:status:"
                 + "firstLevelContainer:first:container:content:searchContainer:resultTable:tablePanel:groupForm:"

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/java/org/apache/syncope/fit/console/DisplayAttributesITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/DisplayAttributesITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/DisplayAttributesITCase.java
index 7627467..e0e02b9 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/DisplayAttributesITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/DisplayAttributesITCase.java
@@ -42,7 +42,7 @@ public class DisplayAttributesITCase extends AbstractConsoleITCase {
         wicketTester.clickLink("body:content:body:tabbedPanel:panel:"
                 + "searchResult:container:content:searchContainer:resultTable:"
                 + "tablePanel:groupForm:checkgroup:dataTable:topToolbars:"
-                + "toolbars:1:headers:3:header:label:panelChangeView:changeViewLink");
+                + "toolbars:1:headers:4:header:label:panelChangeView:changeViewLink");
 
         wicketTester.assertComponent(
                 "body:content:body:tabbedPanel:panel:searchResult:outerObjectsRepeater:2:outer", Modal.class);
@@ -54,7 +54,7 @@ public class DisplayAttributesITCase extends AbstractConsoleITCase {
         wicketTester.clickLink("body:content:body:tabbedPanel:panel:"
                 + "searchResult:container:content:searchContainer:resultTable:"
                 + "tablePanel:groupForm:checkgroup:dataTable:topToolbars:"
-                + "toolbars:1:headers:3:header:label:panelChangeView:changeViewLink");
+                + "toolbars:1:headers:4:header:label:panelChangeView:changeViewLink");
 
         wicketTester.assertComponent(
                 "body:content:body:tabbedPanel:panel:searchResult:outerObjectsRepeater:2:outer", Modal.class);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
index b653de8..7356c5c 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AnyObjectITCase.java
@@ -50,6 +50,7 @@ public class AnyObjectITCase extends AbstractITCase {
 
     public static AnyObjectTO getSampleTO(final String location) {
         AnyObjectTO anyObjectTO = new AnyObjectTO();
+        anyObjectTO.setName(location + getUUIDString());
         anyObjectTO.setRealm(SyncopeConstants.ROOT_REALM);
         anyObjectTO.setType("PRINTER");
         anyObjectTO.getPlainAttrs().add(attrTO("location", location + getUUIDString()));

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
index 781f89b..61c9945 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthenticationITCase.java
@@ -432,6 +432,7 @@ public class AuthenticationITCase extends AbstractITCase {
 
         // 3. attempt to create an instance of the type above: fail because no entitlement was assigned
         AnyObjectTO folder = new AnyObjectTO();
+        folder.setName("home");
         folder.setRealm(SyncopeConstants.ROOT_REALM);
         folder.setType(anyTypeKey);
         folder.getPlainAttrs().add(attrTO(path.getKey(), "/home"));

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/java/org/apache/syncope/fit/core/CamelRouteITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/CamelRouteITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/CamelRouteITCase.java
index 20c290f..b355799 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/CamelRouteITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/CamelRouteITCase.java
@@ -24,7 +24,6 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
 import java.util.List;
-import org.apache.commons.collections4.IterableUtils;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.CamelRouteTO;
@@ -123,8 +122,7 @@ public class CamelRouteITCase extends AbstractITCase {
                 + "    </setProperty>\n"
                 + "    <setBody>\n"
                 + "     <groovy>\n"
-                + "       org.apache.commons.collections4."
-                + "CollectionUtils.get(request.body.getPlainAttrs(), 3).getValues().set(0,\"true\")\n"
+                + "request.body.getPlainAttrMap().get(\"camelAttribute\").getValues().set(0,\"true\")\n"
                 + "       return request.body\n"
                 + "     </groovy>\n"
                 + "    </setBody>\n"
@@ -169,7 +167,7 @@ public class CamelRouteITCase extends AbstractITCase {
 
             userTO = createUser(userTO).getAny();
             assertNotNull(userTO);
-            assertEquals("true", IterableUtils.get(userTO.getPlainAttrs(), 3).getValues().get(0));
+            assertEquals("true", userTO.getPlainAttrMap().get("camelAttribute").getValues().get(0));
         } finally {
             doUpdate(oldRoute.getKey(), oldRoute.getContent());
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
new file mode 100644
index 0000000..09a560c
--- /dev/null
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.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.fit.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.patch.AttrPatch;
+import org.apache.syncope.common.lib.patch.MembershipPatch;
+import org.apache.syncope.common.lib.patch.UserPatch;
+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.ClientExceptionType;
+import org.apache.syncope.common.lib.types.PatchOperation;
+import org.apache.syncope.fit.AbstractITCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+@FixMethodOrder(MethodSorters.JVM)
+public class MembershipITCase extends AbstractITCase {
+
+    @Test
+    public void misc() {
+        UserTO user = UserITCase.getUniqueSampleTO("memb@apache.org");
+        user.setRealm("/even/two");
+        user.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1976").build());
+        user.getPlainAttrs().remove(user.getPlainAttrMap().get("ctype"));
+
+        // the group 034740a9-fa10-453b-af37-dc7897e98fb1 has USER type extensions for 'csv' and 'other' 
+        // any type classes
+        MembershipTO membership = new MembershipTO.Builder().group("034740a9-fa10-453b-af37-dc7897e98fb1").build();
+        membership.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1977").build());
+
+        // 'fullname' is in 'minimal user', so it is not allowed for this membership
+        membership.getPlainAttrs().add(new AttrTO.Builder().schema("fullname").value("discarded").build());
+
+        user.getMemberships().add(membership);
+
+        // user creation fails because of fullname
+        try {
+            createUser(user);
+            fail();
+        } catch (SyncopeClientException e) {
+            assertEquals(ClientExceptionType.InvalidUser, e.getType());
+            assertTrue(e.getMessage().contains("InvalidPlainAttr: fullname not allowed for membership of group"));
+        }
+
+        // remove fullname and try again
+        CollectionUtils.filterInverse(membership.getPlainAttrs(), new Predicate<AttrTO>() {
+
+            @Override
+            public boolean evaluate(final AttrTO object) {
+                return "fullname".equals(object.getSchema());
+            }
+        });
+        try {
+            user = createUser(user).getAny();
+
+            // 1. verify that 'aLong' is correctly populated for user
+            assertEquals(1, user.getPlainAttrMap().get("aLong").getValues().size());
+            assertEquals("1976", user.getPlainAttrMap().get("aLong").getValues().get(0));
+
+            // 2. verify that 'aLong' is correctly populated for user's membership
+            assertEquals(1, user.getMemberships().size());
+            membership = user.getMembershipMap().get("034740a9-fa10-453b-af37-dc7897e98fb1");
+            assertNotNull(membership);
+            assertEquals(1, membership.getPlainAttrMap().get("aLong").getValues().size());
+            assertEquals("1977", membership.getPlainAttrMap().get("aLong").getValues().get(0));
+
+            // 3. verify that derived attrbutes from 'csv' and 'other' are also populated for user's membership
+            assertFalse(membership.getDerAttrMap().get("csvuserid").getValues().isEmpty());
+            assertFalse(membership.getDerAttrMap().get("noschema").getValues().isEmpty());
+
+            // update user - change some values and add new membership attribute
+            UserPatch userPatch = new UserPatch();
+            userPatch.setKey(user.getKey());
+
+            userPatch.getPlainAttrs().add(new AttrPatch.Builder().
+                    attrTO(new AttrTO.Builder().schema("aLong").value("1977").build()).build());
+
+            MembershipPatch membershipPatch = new MembershipPatch.Builder().group(membership.getGroupKey()).build();
+            membershipPatch.getPlainAttrs().add(new AttrPatch.Builder().
+                    attrTO(new AttrTO.Builder().schema("aLong").value("1976").build()).build());
+            membershipPatch.getPlainAttrs().add(new AttrPatch.Builder().
+                    attrTO(new AttrTO.Builder().schema("ctype").value("membership type").build()).build());
+            userPatch.getMemberships().add(membershipPatch);
+
+            user = updateUser(userPatch).getAny();
+
+            // 4. verify that 'aLong' is correctly populated for user
+            assertEquals(1, user.getPlainAttrMap().get("aLong").getValues().size());
+            assertEquals("1977", user.getPlainAttrMap().get("aLong").getValues().get(0));
+            assertFalse(user.getPlainAttrMap().containsKey("ctype"));
+
+            // 5. verify that 'aLong' is correctly populated for user's membership
+            assertEquals(1, user.getMemberships().size());
+            membership = user.getMembershipMap().get("034740a9-fa10-453b-af37-dc7897e98fb1");
+            assertNotNull(membership);
+            assertEquals(1, membership.getPlainAttrMap().get("aLong").getValues().size());
+            assertEquals("1976", membership.getPlainAttrMap().get("aLong").getValues().get(0));
+
+            // 6. verify that 'ctype' is correctly populated for user's membership
+            assertEquals("membership type", membership.getPlainAttrMap().get("ctype").getValues().get(0));
+
+            // finally remove membership
+            userPatch = new UserPatch();
+            userPatch.setKey(user.getKey());
+
+            membershipPatch = new MembershipPatch.Builder().group(membership.getGroupKey()).
+                    operation(PatchOperation.DELETE).build();
+            userPatch.getMemberships().add(membershipPatch);
+
+            user = updateUser(userPatch).getAny();
+
+            assertTrue(user.getMemberships().isEmpty());
+        } finally {
+            if (user.getKey() != null) {
+                userService.delete(user.getKey());
+            }
+        }
+    }
+
+    @Test
+    public void deleteUserWithMembership() {
+        UserTO user = UserITCase.getUniqueSampleTO("memb@apache.org");
+        user.setRealm("/even/two");
+        user.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1976").build());
+
+        MembershipTO membership = new MembershipTO.Builder().group("034740a9-fa10-453b-af37-dc7897e98fb1").build();
+        membership.getPlainAttrs().add(new AttrTO.Builder().schema("aLong").value("1977").build());
+        user.getMemberships().add(membership);
+
+        user = createUser(user).getAny();
+        assertNotNull(user.getKey());
+
+        userService.delete(user.getKey());
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
index 5a76218..4e4af92 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserITCase.java
@@ -646,10 +646,9 @@ public class UserITCase extends AbstractITCase {
         userPatch.getPlainAttrs().add(attrAddReplacePatch("fullname", newFullName));
 
         userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                membershipTO(new MembershipTO.Builder().
-                        group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build()).build());
+                group("f779c0d4-633b-4be5-8f57-32eb478a3ca5").build());
         userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                membershipTO(userTO.getMemberships().get(0)).build());
+                group(userTO.getMemberships().get(0).getGroupKey()).build());
 
         userTO = updateUser(userPatch).getAny();
         assertNotNull(userTO);
@@ -1218,7 +1217,7 @@ public class UserITCase extends AbstractITCase {
         userPatch.setKey(userTO.getKey());
 
         userPatch.getMemberships().add(new MembershipPatch.Builder().
-                operation(PatchOperation.DELETE).membershipTO(userTO.getMemberships().get(0)).build());
+                operation(PatchOperation.DELETE).group(userTO.getMemberships().get(0).getGroupKey()).build());
 
         userTO = updateUser(userPatch).getAny();
         assertNotNull(userTO);
@@ -1253,7 +1252,7 @@ public class UserITCase extends AbstractITCase {
         userPatch.setKey(userTO.getKey());
 
         userPatch.getMemberships().add(new MembershipPatch.Builder().
-                operation(PatchOperation.DELETE).membershipTO(userTO.getMemberships().get(0)).build());
+                operation(PatchOperation.DELETE).group(userTO.getMemberships().get(0).getGroupKey()).build());
 
         userTO = updateUser(userPatch).getAny();
         assertNotNull(userTO);
@@ -1635,7 +1634,7 @@ public class UserITCase extends AbstractITCase {
         UserPatch userPatch = new UserPatch();
         userPatch.setKey(userTO.getKey());
         userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.DELETE).
-                membershipTO(userTO.getMemberships().get(0)).build());
+                group(userTO.getMemberships().get(0).getGroupKey()).build());
 
         userTO = updateUser(userPatch).getAny();
         assertTrue(userTO.getResources().contains(RESOURCE_NAME_LDAP));
@@ -2503,7 +2502,7 @@ public class UserITCase extends AbstractITCase {
             UserPatch userPatch = new UserPatch();
             userPatch.setKey(userTO.getKey());
             userPatch.getMemberships().add(new MembershipPatch.Builder().operation(PatchOperation.ADD_REPLACE).
-                    membershipTO(new MembershipTO.Builder().group(group.getKey()).build()).build());
+                    group(group.getKey()).build());
 
             ProvisioningResult<UserTO> result = updateUser(userPatch);
             assertNotNull(result);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
index 6d412a8..beb6c6e 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserSelfITCase.java
@@ -182,8 +182,7 @@ public class UserSelfITCase extends AbstractITCase {
         userPatch.setUsername(new StringReplacePatchItem.Builder().value(created.getUsername() + "XX").build());
         userPatch.getMemberships().add(new MembershipPatch.Builder().
                 operation(PatchOperation.ADD_REPLACE).
-                membershipTO(new MembershipTO.Builder().
-                        group("bf825fe1-7320-4a54-bd64-143b5c18ab97").build()).
+                group("bf825fe1-7320-4a54-bd64-143b5c18ab97").
                 build());
         userPatch.getResources().add(new StringPatchItem.Builder().
                 operation(PatchOperation.ADD_REPLACE).value(RESOURCE_NAME_TESTDB).build());

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy
index 5ee8d55..a5e1a5e 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/CreateScript.groovy
@@ -37,9 +37,10 @@ def sql = new Sql(connection);
 
 switch ( objectClass ) {  
 case "__PRINTER__":
-  sql.execute("INSERT INTO TESTPRINTER (id, location, lastmodification) values (?,?,?)",
+  sql.execute("INSERT INTO TESTPRINTER (id, printername, location, lastmodification) values (?,?,?,?)",
     [
       id,
+      attributes.get("PRINTERNAME").get(0),
       attributes.get("LOCATION").get(0),
       new Date()
     ])

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/resources/scriptedsql/SchemaScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/SchemaScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/SchemaScript.groovy
index 18ba61d..e13f058 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/SchemaScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/SchemaScript.groovy
@@ -42,6 +42,7 @@ idAIB.setRequired(true);
 
 orgAttrsInfo = new HashSet<AttributeInfo>();
 orgAttrsInfo.add(idAIB.build());
+orgAttrsInfo.add(AttributeInfoBuilder.build("PRINTERNAME", String.class));
 orgAttrsInfo.add(AttributeInfoBuilder.build("LOCATION", String.class));
 // Create the organization Object class
 ObjectClassInfo ociOrg = new ObjectClassInfoBuilder().setType("__PRINTER__").addAllAttributeInfo(orgAttrsInfo).build();

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy
index 3e65581..bb02d80 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/SearchScript.groovy
@@ -84,7 +84,7 @@ if (query != null)  {
 switch ( objectClass ) {
 case "__PRINTER__":
   sql.eachRow("SELECT * FROM TESTPRINTER " + where, 
-    {result.add([__UID__:it.id, __NAME__:it.id, ID:it.id, LOCATION:it.location])} );
+    {result.add([__UID__:it.id, __NAME__:it.id, ID:it.id, PRINTERNAME:it.printername, LOCATION:it.location])} );
   break
 
 default:

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy
index 69f8d79..f7ff18f 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/SyncScript.groovy
@@ -71,7 +71,7 @@ if (action.equalsIgnoreCase("GET_LATEST_SYNC_TOKEN")) {
   }
 
   switch (objectClass) {
-  case "__PRINTER__":    
+  case "__PRINTER__":
     sql.eachRow("SELECT * FROM TESTPRINTER WHERE lastmodification > ${lastmodification}",
       {
         result.add([
@@ -82,6 +82,7 @@ if (action.equalsIgnoreCase("GET_LATEST_SYNC_TOKEN")) {
               __UID__:it.id.toString(),
               __NAME__:it.id.toString(),
               ID:it.id.toString(),
+              PRINTERNAME:it.printername,
               LOCATION:it.location
             ]
           ]);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/resources/scriptedsql/TestScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/TestScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/TestScript.groovy
index 5b8f4b5..1de9d9f 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/TestScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/TestScript.groovy
@@ -28,4 +28,4 @@ import groovy.sql.DataSet;
 log.info("Entering " + action + " Script");
 def sql = new Sql(connection);
 
-sql.eachRow("select * from TESTPRINTER", { println it.uid} );
\ No newline at end of file
+sql.eachRow("select * from TESTPRINTER", { println it.id} );
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/fit/core-reference/src/test/resources/scriptedsql/UpdateScript.groovy
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/resources/scriptedsql/UpdateScript.groovy b/fit/core-reference/src/test/resources/scriptedsql/UpdateScript.groovy
index 4d1ce5e..9df30f8 100644
--- a/fit/core-reference/src/test/resources/scriptedsql/UpdateScript.groovy
+++ b/fit/core-reference/src/test/resources/scriptedsql/UpdateScript.groovy
@@ -51,8 +51,11 @@ def sql = new Sql(connection);
 switch (action) {
 case "UPDATE":
   if (attributes.get("LOCATION").get(0) != null) {
-    sql.executeUpdate("UPDATE TESTPRINTER SET location = ?, lastmodification = ? where id = ?", 
-      [attributes.get("LOCATION").get(0), new Date(), attributes.get("__NAME__").get(0)])
+    sql.executeUpdate("UPDATE TESTPRINTER SET printername = ?, location = ?, lastmodification = ? where id = ?", 
+      [attributes.get("PRINTERNAME").get(0), 
+        attributes.get("LOCATION").get(0), 
+        new Date(), 
+        attributes.get("__NAME__").get(0)])
     
     return attributes.get("__NAME__").get(0);
   }


[2/6] syncope git commit: [SYNCOPE-156] Minor fixes

Posted by il...@apache.org.
[SYNCOPE-156] Minor fixes


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

Branch: refs/heads/SYNCOPE-862
Commit: c1fd63c0e2199afc81b9b3571c60232bdd98023d
Parents: 514cbf4
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Wed Jun 1 08:52:55 2016 +0200
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Wed Jun 1 08:52:55 2016 +0200

----------------------------------------------------------------------
 .../client/console/panels/ConnObjects.java      | 28 +++++++++++++-------
 .../policies/AccountPolicyDirectoryPanel.java   |  2 --
 .../policies/PasswordPolicyDirectoryPanel.java  |  2 --
 .../policies/PolicyRuleWizardBuilder.java       | 24 ++++++++++-------
 .../policies/PullPolicyDirectoryPanel.java      |  2 --
 5 files changed, 33 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/c1fd63c0/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
index f261ddc..5d08ebe 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
@@ -19,6 +19,7 @@
 package org.apache.syncope.client.console.panels;
 
 import java.util.ArrayList;
+import java.util.List;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Transformer;
 import org.apache.syncope.client.console.commons.Constants;
@@ -49,18 +50,27 @@ public class ConnObjects extends Panel implements ModalPanel {
 
         super(BaseModal.CONTENT_ID);
 
-        anyTypes = new AjaxDropDownChoicePanel<>("anyTypes", "anyTypes", new Model<String>(), true);
-        anyTypes.setChoices(CollectionUtils.collect(new ResourceRestClient().read(resource).getProvisions(),
-                new Transformer<ProvisionTO, String>() {
+        List<String> availableAnyTypes =
+                CollectionUtils.collect(new ResourceRestClient().read(resource).getProvisions(),
+                        new Transformer<ProvisionTO, String>() {
 
-            @Override
-            public String transform(final ProvisionTO provision) {
-                return provision.getAnyType();
-            }
-        }, new ArrayList<String>()));
+                    @Override
+                    public String transform(final ProvisionTO provision) {
+                        return provision.getAnyType();
+                    }
+                }, new ArrayList<String>());
+
+        anyTypes = new AjaxDropDownChoicePanel<>("anyTypes", "anyTypes", new Model<String>(), true);
+        anyTypes.setChoices(availableAnyTypes);
         anyTypes.hideLabel();
         anyTypes.setNullValid(false);
-        anyTypes.setDefaultModelObject(AnyTypeKind.USER.name());
+        if (availableAnyTypes.contains(AnyTypeKind.USER.name())) {
+            anyTypes.setDefaultModelObject(AnyTypeKind.USER.name());
+        } else if (availableAnyTypes.contains(AnyTypeKind.GROUP.name())) {
+            anyTypes.setDefaultModelObject(AnyTypeKind.GROUP.name());
+        } else if (!availableAnyTypes.isEmpty()) {
+            anyTypes.setDefaultModelObject(availableAnyTypes.get(0));
+        }
         add(anyTypes);
 
         connObjects = new MultilevelPanel("connObjects") {

http://git-wip-us.apache.org/repos/asf/syncope/blob/c1fd63c0/client/console/src/main/java/org/apache/syncope/client/console/policies/AccountPolicyDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/AccountPolicyDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/AccountPolicyDirectoryPanel.java
index 5671bdd..eceb67f 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/policies/AccountPolicyDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/policies/AccountPolicyDirectoryPanel.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.client.console.policies;
 
-import static org.apache.wicket.Component.ENABLE;
-
 import java.util.List;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanPropertyColumn;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.CollectionPropertyColumn;

http://git-wip-us.apache.org/repos/asf/syncope/blob/c1fd63c0/client/console/src/main/java/org/apache/syncope/client/console/policies/PasswordPolicyDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/PasswordPolicyDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/PasswordPolicyDirectoryPanel.java
index c05f983..50666f8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/policies/PasswordPolicyDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/policies/PasswordPolicyDirectoryPanel.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.client.console.policies;
 
-import static org.apache.wicket.Component.ENABLE;
-
 import java.util.List;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanPropertyColumn;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;

http://git-wip-us.apache.org/repos/asf/syncope/blob/c1fd63c0/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleWizardBuilder.java
index 6d3950f..168195f 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/policies/PolicyRuleWizardBuilder.java
@@ -138,19 +138,23 @@ public class PolicyRuleWizardBuilder
                 }
             });
 
-            final List<String> choices;
-
-            if (type == PolicyType.ACCOUNT) {
-                choices = new ArrayList<>(SyncopeConsoleSession.get().getPlatformInfo().getAccountRules());
-            } else if (type == PolicyType.PASSWORD) {
-                choices = new ArrayList<>(SyncopeConsoleSession.get().getPlatformInfo().getPasswordRules());
-            } else {
-                choices = new ArrayList<>();
+            List<String> choices;
+            switch (type) {
+                case ACCOUNT:
+                    choices = new ArrayList<>(SyncopeConsoleSession.get().getPlatformInfo().getAccountRules());
+                    break;
+
+                case PASSWORD:
+                    choices = new ArrayList<>(SyncopeConsoleSession.get().getPlatformInfo().getPasswordRules());
+                    break;
+
+                default:
+                    choices = new ArrayList<>();
             }
 
             Collections.<String>sort(choices);
             conf.setChoices(choices);
-            
+
             conf.addRequiredLabel();
             add(conf);
         }
@@ -173,7 +177,7 @@ public class PolicyRuleWizardBuilder
                 }
             };
 
-            add(new BeanPanel("bean", bean).setRenderBodyOnly(true));
+            add(new BeanPanel<>("bean", bean).setRenderBodyOnly(true));
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/c1fd63c0/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java
index 99bd048..a313d05 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.client.console.policies;
 
-import static org.apache.wicket.Component.ENABLE;
-
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
 import org.apache.syncope.common.lib.policy.PullPolicySpec;


[3/6] syncope git commit: Updating the contributing page with reference to Git workflow

Posted by il...@apache.org.
Updating the contributing page with reference to Git workflow


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

Branch: refs/heads/SYNCOPE-862
Commit: a7ef4e1fad33642912a397c254f785e9e07ac9b9
Parents: c1fd63c
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Wed Jun 1 09:01:17 2016 +0200
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Wed Jun 1 09:01:17 2016 +0200

----------------------------------------------------------------------
 src/site/xdoc/contributing.xml | 46 ++++++++-----------------------------
 1 file changed, 10 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/a7ef4e1f/src/site/xdoc/contributing.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/contributing.xml b/src/site/xdoc/contributing.xml
index 6f2503d..3b753a9 100644
--- a/src/site/xdoc/contributing.xml
+++ b/src/site/xdoc/contributing.xml
@@ -27,22 +27,22 @@ under the License.
   </properties>
 
   <body>
-    
-    <section name="Looking for ideas?">
-      <div style="width: 700px;" type="helpwanted" project="syncope" description="Apache Syncope"></div>
-      <script src="https://helpwanted.apache.org/widget.js" type="text/javascript"></script>
-    </section>
-    
+   
     <section name="How to contribute?">
       <p>
         The Apache Syncope\u2122 project is actively seeking new contributors to work on all aspects of the project. 
         We need and appreciate all contributions, including documentation help, source code development and feedback.
       </p>
 
+      <subsection name="Looking for ideas?">
+        <div style="width: 700px;" type="helpwanted" project="syncope" description="Apache Syncope"></div>
+        <script src="https://helpwanted.apache.org/widget.js" type="text/javascript"></script>
+      </subsection>
+
       <subsection name="Code">
         <ul>
           <li>If you have found an issue or you want to propose a new feature, post a message to the 
-            <a href="mailing-lists.html">Syncope User's list</a> to discuss it.
+            <a href="mailing-lists.html">Syncope Dev list or jump on IRC</a> to discuss it.
           </li>
           <li>Search existing 
             <a href="https://issues.apache.org/jira/secure/IssueNavigator.jspa" rel="nofollow">issues</a> to see 
@@ -52,16 +52,7 @@ under the License.
             <a href="https://issues.apache.org/jira/browse/SYNCOPE">JIRA</a> issue.
           </li>
           <li>Develop / describe a test case to demonstrate the issue.</li>
-          <li>Attach the new test to the JIRA issue.</li>
-          <li>If you have also developed a fix for the raised issue, either
-            <ul>
-              <li>attach a patch to it; here are some useful 
-                <a href="https://commons.apache.org/patches.html">guidelines</a> about how to correctly generate a patch.
-              </li>
-              <li>open a <a href="https://github.com/apache/syncope/pulls">pull request</a> - don't forget to
-                mention the JIRA issue id (e.g. SYNCOPE-XXX) opened above in the commit log message</li>
-            </ul>
-          </li>
+          <li>Review and apply our <a href="https://cwiki.apache.org/confluence/display/SYNCOPE/Git+workflow">Git workflow</a>.</li>
         </ul>
       </subsection>
 
@@ -69,31 +60,14 @@ under the License.
         <p>The website is managed via the 
           <a href="http://maven.apache.org/plugins/maven-site-plugin/">maven-site-plugin</a> and the guides are being
           maintained with <a href="http://asciidoctor.org/">Asciidoctor</a>, hence contributing site content or
-          guides is similar to contributing source code: create a new issue on JIRA and attach a GIT patch to it.
+          guides is similar to contributing <a href="#Code">source code</a>.
         </p>
         <p>The project 
           <a href="http://cwiki.apache.org/confluence/display/SYNCOPE">Wiki</a> is also available to gather any other 
           kind of documentation or contribution you would like to contribute, and does not require any GIT, Maven or 
           other technical skills.
         </p>
-      </subsection>
-    
-      <subsection name="Quick references">
-        <ul>
-          <li>
-            Discussion occurs on the 
-            <a href="mailing-lists.html">mailing lists</a>
-          </li>
-          <li>
-            Information on accessing the project source code is 
-            <a href="source-repository.html">here</a>.
-          </li>
-          <li>
-            Bugs and other issues can be posted on 
-            <a href="https://issues.apache.org/jira/browse/SYNCOPE">JIRA</a>
-          </li>
-        </ul>
-      </subsection>
+      </subsection>    
     </section>
     
     <section name="How do I become a contributor or a committer?">


[5/6] syncope git commit: [SYNCOPE-862] Preliminary work

Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
index 38d4add..af5220f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAGroupDAO.java
@@ -44,6 +44,7 @@ import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
 import org.apache.syncope.core.persistence.api.dao.search.AssignableCond;
 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
 import org.apache.syncope.core.persistence.api.entity.Any;
@@ -52,9 +53,11 @@ import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
+import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
 import org.apache.syncope.core.persistence.jpa.entity.anyobject.JPAAMembership;
 import org.apache.syncope.core.persistence.jpa.entity.group.JPATypeExtension;
@@ -72,6 +75,9 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
     @Autowired
     private UserDAO userDAO;
 
+    @Autowired
+    private PlainAttrDAO plainAttrDAO;
+
     @Override
     protected AnyUtils init() {
         return new JPAAnyUtilsFactory().getInstance(AnyTypeKind.GROUP);
@@ -242,16 +248,30 @@ public class JPAGroupDAO extends AbstractAnyDAO<Group> implements GroupDAO {
     @Override
     public void delete(final Group group) {
         for (AMembership membership : findAMemberships(group)) {
-            membership.getLeftEnd().getMemberships().remove(membership);
-            anyObjectDAO.save(membership.getLeftEnd());
+            AnyObject leftEnd = membership.getLeftEnd();
+            leftEnd.getMemberships().remove(membership);
+            membership.setRightEnd(null);
+            for (APlainAttr attr : leftEnd.getPlainAttrs(membership)) {
+                leftEnd.remove(attr);
+                attr.setOwner(null);
+                attr.setMembership(null);
+                plainAttrDAO.delete(attr);
+            }
 
-            entityManager().remove(membership);
+            anyObjectDAO.save(leftEnd);
         }
         for (UMembership membership : findUMemberships(group)) {
-            membership.getLeftEnd().getMemberships().remove(membership);
-            userDAO.save(membership.getLeftEnd());
+            User leftEnd = membership.getLeftEnd();
+            leftEnd.getMemberships().remove(membership);
+            membership.setRightEnd(null);
+            for (UPlainAttr attr : leftEnd.getPlainAttrs(membership)) {
+                leftEnd.remove(attr);
+                attr.setOwner(null);
+                attr.setMembership(null);
+                plainAttrDAO.delete(attr);
+            }
 
-            entityManager().remove(membership);
+            userDAO.save(leftEnd);
         }
 
         entityManager().remove(group);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
index 3e8a38c..d4ba926 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAPlainAttrDAO.java
@@ -68,7 +68,7 @@ public class JPAPlainAttrDAO extends AbstractDAO<PlainAttr<?>> implements PlainA
     @SuppressWarnings("unchecked")
     public <T extends PlainAttr<?>> void delete(final T plainAttr) {
         if (plainAttr.getOwner() != null) {
-            ((Any<T>) plainAttr.getOwner()).getPlainAttrs().remove(plainAttr);
+            ((Any<T>) plainAttr.getOwner()).remove(plainAttr);
         }
 
         entityManager().remove(plainAttr);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
index 496e689..cf3ede1 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractAny.java
@@ -25,14 +25,11 @@ import javax.persistence.FetchType;
 import javax.persistence.ManyToOne;
 import javax.persistence.MappedSuperclass;
 import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.IterableUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.core.provisioning.api.utils.EntityUtils;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
-import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResource;
 import org.apache.syncope.core.persistence.jpa.validation.entity.AnyCheck;
 
 @AnyCheck
@@ -81,33 +78,8 @@ public abstract class AbstractAny<P extends PlainAttr<?>> extends AbstractAnnota
     }
 
     @Override
-    public P getPlainAttr(final String plainSchemaName) {
-        return IterableUtils.find(getPlainAttrs(), new Predicate<P>() {
-
-            @Override
-            public boolean evaluate(final P plainAttr) {
-                return plainAttr != null && plainAttr.getSchema() != null
-                        && plainSchemaName.equals(plainAttr.getSchema().getKey());
-            }
-        });
-    }
-
-    protected abstract List<JPAExternalResource> internalGetResources();
-
-    @Override
-    public boolean add(final ExternalResource resource) {
-        checkType(resource, JPAExternalResource.class);
-        return internalGetResources().add((JPAExternalResource) resource);
-    }
-
-    @Override
     public List<String> getResourceNames() {
         return CollectionUtils.collect(
                 getResources(), EntityUtils.<ExternalResource>keyTransformer(), new ArrayList<String>());
     }
-
-    @Override
-    public List<? extends ExternalResource> getResources() {
-        return internalGetResources();
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractGroupableRelatable.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractGroupableRelatable.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractGroupableRelatable.java
new file mode 100644
index 0000000..a2a41fa
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/AbstractGroupableRelatable.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.entity;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
+import org.apache.syncope.core.persistence.api.entity.Membership;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
+import org.apache.syncope.core.persistence.api.entity.Relationship;
+import org.apache.syncope.core.persistence.api.entity.RelationshipType;
+
+public abstract class AbstractGroupableRelatable<
+        L extends Any<P>, 
+        M extends Membership<L>, 
+        P extends GroupablePlainAttr<L, M>,
+        R extends Any<?>,
+        REL extends Relationship<L, R>>
+        extends AbstractAny<P> implements GroupableRelatable<L, M, P, R, REL> {
+
+    private static final long serialVersionUID = -2269285197388729673L;
+
+    protected abstract List<? extends P> internalGetPlainAttrs();
+
+    @Override
+    public boolean remove(final P attr) {
+        return internalGetPlainAttrs().remove(attr);
+    }
+
+    @Override
+    public P getPlainAttr(final String plainSchemaName) {
+        return IterableUtils.find(internalGetPlainAttrs(), new Predicate<P>() {
+
+            @Override
+            public boolean evaluate(final P plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && plainAttr.getMembership() == null
+                        && plainSchemaName.equals(plainAttr.getSchema().getKey());
+            }
+        });
+    }
+
+    @Override
+    public P getPlainAttr(final String plainSchemaName, final Membership<?> membership) {
+        return IterableUtils.find(internalGetPlainAttrs(), new Predicate<P>() {
+
+            @Override
+            public boolean evaluate(final P plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && plainAttr.getMembership() != null && plainAttr.getMembership().equals(membership)
+                        && plainSchemaName.equals(plainAttr.getSchema().getKey());
+            }
+        });
+    }
+
+    @Override
+    public List<? extends P> getPlainAttrs() {
+        return CollectionUtils.select(internalGetPlainAttrs(), new Predicate<P>() {
+
+            @Override
+            public boolean evaluate(final P plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && plainAttr.getMembership() == null;
+            }
+        }, new ArrayList<P>());
+    }
+
+    @Override
+    public Collection<? extends P> getPlainAttrs(final String plainSchemaName) {
+        return CollectionUtils.select(internalGetPlainAttrs(), new Predicate<P>() {
+
+            @Override
+            public boolean evaluate(final P plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && plainSchemaName.equals(plainAttr.getSchema().getKey());
+            }
+        });
+    }
+
+    @Override
+    public Collection<? extends P> getPlainAttrs(final Membership<?> membership) {
+        return CollectionUtils.select(internalGetPlainAttrs(), new Predicate<P>() {
+
+            @Override
+            public boolean evaluate(final P plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && membership.equals(plainAttr.getMembership());
+            }
+        });
+    }
+
+    @Override
+    public M getMembership(final String groupKey) {
+        return IterableUtils.find(getMemberships(), new Predicate<M>() {
+
+            @Override
+            public boolean evaluate(final M membership) {
+                return groupKey != null && groupKey.equals(membership.getRightEnd().getKey());
+            }
+        });
+    }
+
+    @Override
+    public REL getRelationship(final RelationshipType relationshipType, final String otherEndKey) {
+        return IterableUtils.find(getRelationships(), new Predicate<REL>() {
+
+            @Override
+            public boolean evaluate(final REL relationship) {
+                return otherEndKey != null && otherEndKey.equals(relationship.getRightEnd().getKey())
+                        && ((relationshipType == null && relationship.getType() == null)
+                        || (relationshipType != null && relationshipType.equals(relationship.getType())));
+            }
+        });
+    }
+
+    @Override
+    public Collection<? extends REL> getRelationships(final RelationshipType relationshipType) {
+        return CollectionUtils.select(getRelationships(), new Predicate<REL>() {
+
+            @Override
+            public boolean evaluate(final REL relationship) {
+                return relationshipType != null && relationshipType.equals(relationship.getType());
+            }
+        });
+    }
+
+    @Override
+    public Collection<? extends REL> getRelationships(final String otherEndKey) {
+        return CollectionUtils.select(getRelationships(), new Predicate<REL>() {
+
+            @Override
+            public boolean evaluate(final REL relationship) {
+                return otherEndKey != null && otherEndKey.equals(relationship.getRightEnd().getKey());
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
index a4d6eea..5c1b203 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAAnyUtils.java
@@ -26,6 +26,7 @@ import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
@@ -342,17 +343,17 @@ public class JPAAnyUtils implements AnyUtils {
 
     @Transactional(readOnly = true)
     @Override
-    public <S extends Schema> Set<S> getAllowedSchemas(final Any<?> any, final Class<S> reference) {
-        Set<S> schemas = new HashSet<>();
+    public <S extends Schema> AllowedSchemas<S> getAllowedSchemas(final Any<?> any, final Class<S> reference) {
+        AllowedSchemas<S> result = null;
 
         if (any instanceof User) {
-            schemas.addAll(userDAO.findAllowedSchemas((User) any, reference));
+            result = userDAO.findAllowedSchemas((User) any, reference);
         } else if (any instanceof Group) {
-            schemas.addAll(groupDAO.findAllowedSchemas((Group) any, reference));
+            result = groupDAO.findAllowedSchemas((Group) any, reference);
         } else if (any instanceof AnyObject) {
-            schemas.addAll(anyObjectDAO.findAllowedSchemas((AnyObject) any, reference));
+            result = anyObjectDAO.findAllowedSchemas((AnyObject) any, reference);
         }
 
-        return schemas;
+        return result;
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttr.java
index f9a8151..044faae 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAPlainAttr.java
@@ -27,9 +27,11 @@ import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
 import javax.validation.Valid;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrValue;
@@ -37,7 +39,8 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttr;
 
 @Entity
-@Table(name = JPAAPlainAttr.TABLE)
+@Table(name = JPAAPlainAttr.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "owner_id", "membership_id", "schema_id" }))
 public class JPAAPlainAttr extends AbstractPlainAttr<AnyObject> implements APlainAttr {
 
     private static final long serialVersionUID = 8066058729580952116L;
@@ -47,6 +50,12 @@ public class JPAAPlainAttr extends AbstractPlainAttr<AnyObject> implements APlai
     @ManyToOne(fetch = FetchType.EAGER)
     private JPAAnyObject owner;
 
+    /**
+     * The membership of this attribute; might be {@code NULL} if this attribute is not related to a membership.
+     */
+    @ManyToOne(fetch = FetchType.EAGER)
+    private JPAAMembership membership;
+
     @OneToMany(cascade = CascadeType.MERGE, orphanRemoval = true, mappedBy = "attribute")
     @Valid
     private List<JPAAPlainAttrValue> values = new ArrayList<>();
@@ -67,6 +76,17 @@ public class JPAAPlainAttr extends AbstractPlainAttr<AnyObject> implements APlai
     }
 
     @Override
+    public AMembership getMembership() {
+        return membership;
+    }
+
+    @Override
+    public void setMembership(final AMembership membership) {
+        checkType(membership, JPAAMembership.class);
+        this.membership = (JPAAMembership) membership;
+    }
+
+    @Override
     protected boolean addForMultiValue(final PlainAttrValue attrValue) {
         checkType(attrValue, JPAAPlainAttrValue.class);
         return values.add((JPAAPlainAttrValue) attrValue);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
index 44f55df..d790082 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/anyobject/JPAAnyObject.java
@@ -19,10 +19,10 @@
 package org.apache.syncope.core.persistence.jpa.entity.anyobject;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import javax.persistence.Cacheable;
 import javax.persistence.CascadeType;
+import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
@@ -33,17 +33,14 @@ import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.IterableUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
-import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttr;
 import org.apache.syncope.core.persistence.api.entity.anyobject.ARelationship;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractAny;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractGroupableRelatable;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyType;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyTypeClass;
 import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResource;
@@ -51,12 +48,18 @@ import org.apache.syncope.core.persistence.jpa.entity.resource.JPAExternalResour
 @Entity
 @Table(name = JPAAnyObject.TABLE)
 @Cacheable
-public class JPAAnyObject extends AbstractAny<APlainAttr> implements AnyObject {
+public class JPAAnyObject
+        extends AbstractGroupableRelatable<AnyObject, AMembership, APlainAttr, AnyObject, ARelationship>
+        implements AnyObject {
 
     private static final long serialVersionUID = 9063766472970643492L;
 
     public static final String TABLE = "AnyObject";
 
+    @Column(unique = true)
+    @NotNull
+    private String name;
+
     @NotNull
     @ManyToOne(fetch = FetchType.EAGER, optional = false)
     private JPAAnyType type;
@@ -79,15 +82,25 @@ public class JPAAnyObject extends AbstractAny<APlainAttr> implements AnyObject {
             @JoinColumn(name = "anyTypeClass_id"))
     private List<JPAAnyTypeClass> auxClasses = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "leftEnd")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "leftEnd")
     @Valid
     private List<JPAARelationship> relationships = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "leftEnd")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "leftEnd")
     @Valid
     private List<JPAAMembership> memberships = new ArrayList<>();
 
     @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    @Override
     public AnyType getType() {
         return type;
     }
@@ -99,22 +112,28 @@ public class JPAAnyObject extends AbstractAny<APlainAttr> implements AnyObject {
     }
 
     @Override
+    public boolean add(final ExternalResource resource) {
+        checkType(resource, JPAExternalResource.class);
+        return resources.add((JPAExternalResource) resource);
+    }
+
+    @Override
+    public List<? extends ExternalResource> getResources() {
+        return resources;
+    }
+
+    @Override
     public boolean add(final APlainAttr attr) {
         checkType(attr, JPAAPlainAttr.class);
         return plainAttrs.add((JPAAPlainAttr) attr);
     }
 
     @Override
-    public List<? extends APlainAttr> getPlainAttrs() {
+    protected List<? extends APlainAttr> internalGetPlainAttrs() {
         return plainAttrs;
     }
 
     @Override
-    protected List<JPAExternalResource> internalGetResources() {
-        return resources;
-    }
-
-    @Override
     public boolean add(final AnyTypeClass auxClass) {
         checkType(auxClass, JPAAnyTypeClass.class);
         return this.auxClasses.add((JPAAnyTypeClass) auxClass);
@@ -132,41 +151,6 @@ public class JPAAnyObject extends AbstractAny<APlainAttr> implements AnyObject {
     }
 
     @Override
-    public ARelationship getRelationship(final RelationshipType relationshipType, final String anyObjectKey) {
-        return IterableUtils.find(getRelationships(), new Predicate<ARelationship>() {
-
-            @Override
-            public boolean evaluate(final ARelationship relationship) {
-                return anyObjectKey != null && anyObjectKey.equals(relationship.getRightEnd().getKey())
-                        && ((relationshipType == null && relationship.getType() == null)
-                        || (relationshipType != null && relationshipType.equals(relationship.getType())));
-            }
-        });
-    }
-
-    @Override
-    public Collection<? extends ARelationship> getRelationships(final RelationshipType relationshipType) {
-        return CollectionUtils.select(getRelationships(), new Predicate<ARelationship>() {
-
-            @Override
-            public boolean evaluate(final ARelationship relationship) {
-                return relationshipType != null && relationshipType.equals(relationship.getType());
-            }
-        });
-    }
-
-    @Override
-    public Collection<? extends ARelationship> getRelationships(final String anyObjectKey) {
-        return CollectionUtils.select(getRelationships(), new Predicate<ARelationship>() {
-
-            @Override
-            public boolean evaluate(final ARelationship relationship) {
-                return anyObjectKey != null && anyObjectKey.equals(relationship.getRightEnd().getKey());
-            }
-        });
-    }
-
-    @Override
     public List<? extends ARelationship> getRelationships() {
         return relationships;
     }
@@ -178,17 +162,6 @@ public class JPAAnyObject extends AbstractAny<APlainAttr> implements AnyObject {
     }
 
     @Override
-    public AMembership getMembership(final String groupKey) {
-        return IterableUtils.find(getMemberships(), new Predicate<AMembership>() {
-
-            @Override
-            public boolean evaluate(final AMembership membership) {
-                return groupKey != null && groupKey.equals(membership.getRightEnd().getKey());
-            }
-        });
-    }
-
-    @Override
     public List<? extends AMembership> getMemberships() {
         return memberships;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
index 1ceaaa7..88ce38f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/conf/JPAConf.java
@@ -47,7 +47,7 @@ public class JPAConf extends AbstractProvidedKeyEntity implements Conf {
 
     public static final String TABLE = "SyncopeConf";
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "owner")
     @Valid
     private List<JPACPlainAttr> plainAttrs = new ArrayList<>();
 
@@ -58,6 +58,12 @@ public class JPAConf extends AbstractProvidedKeyEntity implements Conf {
     }
 
     @Override
+    public boolean remove(final CPlainAttr attr) {
+        checkType(attr, JPACPlainAttr.class);
+        return plainAttrs.remove((JPACPlainAttr) attr);
+    }
+
+    @Override
     public CPlainAttr getPlainAttr(final String plainSchemaName) {
         return IterableUtils.find(plainAttrs, new Predicate<CPlainAttr>() {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttr.java
index 644fa27..53cf335 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGPlainAttr.java
@@ -27,6 +27,7 @@ import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
 import javax.validation.Valid;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
@@ -37,7 +38,8 @@ import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttr;
 
 @Entity
-@Table(name = JPAGPlainAttr.TABLE)
+@Table(name = JPAGPlainAttr.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "owner_id", "schema_id" }))
 public class JPAGPlainAttr extends AbstractPlainAttr<Group> implements GPlainAttr {
 
     private static final long serialVersionUID = 2848159565890995780L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
index 8afb1ae..bcfa9b0 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/group/JPAGroup.java
@@ -44,6 +44,7 @@ import org.apache.syncope.core.persistence.api.entity.anyobject.ADynGroupMembers
 import org.apache.syncope.core.persistence.api.entity.group.GPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.user.UDynGroupMembership;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractAny;
@@ -74,7 +75,7 @@ public class JPAGroup extends AbstractAny<GPlainAttr> implements Group {
     @ManyToOne
     private JPAGroup groupOwner;
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "owner")
     @Valid
     private List<JPAGPlainAttr> plainAttrs = new ArrayList<>();
 
@@ -104,6 +105,16 @@ public class JPAGroup extends AbstractAny<GPlainAttr> implements Group {
     private List<JPATypeExtension> typeExtensions = new ArrayList<>();
 
     @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    @Override
     public AnyType getType() {
         return ApplicationContextProvider.getBeanFactory().getBean(AnyTypeDAO.class).findGroup();
     }
@@ -114,18 +125,14 @@ public class JPAGroup extends AbstractAny<GPlainAttr> implements Group {
     }
 
     @Override
-    protected List<JPAExternalResource> internalGetResources() {
-        return resources;
-    }
-
-    @Override
-    public String getName() {
-        return name;
+    public boolean add(final ExternalResource resource) {
+        checkType(resource, JPAExternalResource.class);
+        return resources.add((JPAExternalResource) resource);
     }
 
     @Override
-    public void setName(final String name) {
-        this.name = name;
+    public List<? extends ExternalResource> getResources() {
+        return resources;
     }
 
     @Override
@@ -157,6 +164,24 @@ public class JPAGroup extends AbstractAny<GPlainAttr> implements Group {
     }
 
     @Override
+    public boolean remove(final GPlainAttr attr) {
+        checkType(attr, JPAGPlainAttr.class);
+        return plainAttrs.remove((JPAGPlainAttr) attr);
+    }
+
+    @Override
+    public GPlainAttr getPlainAttr(final String plainSchemaName) {
+        return IterableUtils.find(getPlainAttrs(), new Predicate<GPlainAttr>() {
+
+            @Override
+            public boolean evaluate(final GPlainAttr plainAttr) {
+                return plainAttr != null && plainAttr.getSchema() != null
+                        && plainSchemaName.equals(plainAttr.getSchema().getKey());
+            }
+        });
+    }
+
+    @Override
     public List<? extends GPlainAttr> getPlainAttrs() {
         return plainAttrs;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
index 438994f..1d00f89 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/resource/JPAMappingItem.java
@@ -183,6 +183,10 @@ public class JPAMappingItem extends AbstractGeneratedKeyEntity implements Mappin
                 name = "groupOwnerSchema";
                 break;
 
+            case AnyObjectName:
+                name = "anyObjectName";
+                break;
+                
             default:
                 name = intAttrName;
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttr.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttr.java
index 84c9c84..bdabf2c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttr.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUPlainAttr.java
@@ -27,9 +27,11 @@ import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
 import javax.validation.Valid;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
+import org.apache.syncope.core.persistence.api.entity.user.UMembership;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrValue;
@@ -37,7 +39,8 @@ import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.persistence.jpa.entity.AbstractPlainAttr;
 
 @Entity
-@Table(name = JPAUPlainAttr.TABLE)
+@Table(name = JPAUPlainAttr.TABLE, uniqueConstraints =
+        @UniqueConstraint(columnNames = { "owner_id", "membership_id", "schema_id" }))
 public class JPAUPlainAttr extends AbstractPlainAttr<User> implements UPlainAttr {
 
     private static final long serialVersionUID = 6333601983691157406L;
@@ -51,6 +54,12 @@ public class JPAUPlainAttr extends AbstractPlainAttr<User> implements UPlainAttr
     private JPAUser owner;
 
     /**
+     * The membership of this attribute; might be {@code NULL} if this attribute is not related to a membership.
+     */
+    @ManyToOne(fetch = FetchType.EAGER)
+    private JPAUMembership membership;
+
+    /**
      * Values of this attribute (if schema is not UNIQUE).
      */
     @OneToMany(cascade = CascadeType.MERGE, orphanRemoval = true, mappedBy = "attribute")
@@ -76,6 +85,17 @@ public class JPAUPlainAttr extends AbstractPlainAttr<User> implements UPlainAttr
     }
 
     @Override
+    public UMembership getMembership() {
+        return membership;
+    }
+
+    @Override
+    public void setMembership(final UMembership membership) {
+        checkType(membership, JPAUMembership.class);
+        this.membership = (JPAUMembership) membership;
+    }
+
+    @Override
     protected boolean addForMultiValue(final PlainAttrValue attrValue) {
         checkType(attrValue, JPAUPlainAttrValue.class);
         return values.add((JPAUPlainAttrValue) attrValue);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
index a0ecf00..f207cfe 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java
@@ -20,7 +20,6 @@ package org.apache.syncope.core.persistence.jpa.entity.user;
 
 import java.util.ArrayList;
 import java.util.Calendar;
-import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import javax.persistence.Basic;
@@ -47,9 +46,6 @@ import javax.validation.Valid;
 import javax.validation.constraints.Max;
 import javax.validation.constraints.Min;
 import javax.validation.constraints.NotNull;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.IterableUtils;
-import org.apache.commons.collections4.Predicate;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
 import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion;
 import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
@@ -62,18 +58,21 @@ import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
-import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
 import org.apache.syncope.core.persistence.api.entity.user.URelationship;
-import org.apache.syncope.core.persistence.jpa.entity.AbstractAny;
+import org.apache.syncope.core.persistence.jpa.entity.AbstractGroupableRelatable;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyTypeClass;
 import org.apache.syncope.core.persistence.jpa.entity.JPARole;
 
 @Entity
 @Table(name = JPAUser.TABLE)
 @Cacheable
-public class JPAUser extends AbstractAny<UPlainAttr> implements User {
+public class JPAUser
+        extends AbstractGroupableRelatable<User, UMembership, UPlainAttr, AnyObject, URelationship>
+        implements User {
 
     private static final long serialVersionUID = -3905046855521446823L;
 
@@ -172,11 +171,11 @@ public class JPAUser extends AbstractAny<UPlainAttr> implements User {
             @JoinColumn(name = "anyTypeClass_id"))
     private List<JPAAnyTypeClass> auxClasses = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "leftEnd")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "leftEnd")
     @Valid
     private List<JPAURelationship> relationships = new ArrayList<>();
 
-    @OneToMany(cascade = CascadeType.ALL, mappedBy = "leftEnd")
+    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "leftEnd")
     @Valid
     private List<JPAUMembership> memberships = new ArrayList<>();
 
@@ -197,7 +196,13 @@ public class JPAUser extends AbstractAny<UPlainAttr> implements User {
     }
 
     @Override
-    protected List<JPAExternalResource> internalGetResources() {
+    public boolean add(final ExternalResource resource) {
+        checkType(resource, JPAExternalResource.class);
+        return resources.add((JPAExternalResource) resource);
+    }
+
+    @Override
+    public List<? extends ExternalResource> getResources() {
         return resources;
     }
 
@@ -270,7 +275,7 @@ public class JPAUser extends AbstractAny<UPlainAttr> implements User {
     }
 
     @Override
-    public List<? extends UPlainAttr> getPlainAttrs() {
+    protected List<? extends UPlainAttr> internalGetPlainAttrs() {
         return plainAttrs;
     }
 
@@ -471,41 +476,6 @@ public class JPAUser extends AbstractAny<UPlainAttr> implements User {
     }
 
     @Override
-    public URelationship getRelationship(final RelationshipType relationshipType, final String anyObjectKey) {
-        return IterableUtils.find(getRelationships(), new Predicate<URelationship>() {
-
-            @Override
-            public boolean evaluate(final URelationship relationship) {
-                return anyObjectKey != null && anyObjectKey.equals(relationship.getRightEnd().getKey())
-                        && ((relationshipType == null && relationship.getType() == null)
-                        || (relationshipType != null && relationshipType.equals(relationship.getType())));
-            }
-        });
-    }
-
-    @Override
-    public Collection<? extends URelationship> getRelationships(final RelationshipType relationshipType) {
-        return CollectionUtils.select(getRelationships(), new Predicate<URelationship>() {
-
-            @Override
-            public boolean evaluate(final URelationship relationship) {
-                return relationshipType != null && relationshipType.equals(relationship.getType());
-            }
-        });
-    }
-
-    @Override
-    public Collection<? extends URelationship> getRelationships(final String anyObjectKey) {
-        return CollectionUtils.select(getRelationships(), new Predicate<URelationship>() {
-
-            @Override
-            public boolean evaluate(final URelationship relationship) {
-                return anyObjectKey != null && anyObjectKey.equals(relationship.getRightEnd().getKey());
-            }
-        });
-    }
-
-    @Override
     public List<? extends URelationship> getRelationships() {
         return relationships;
     }
@@ -517,17 +487,6 @@ public class JPAUser extends AbstractAny<UPlainAttr> implements User {
     }
 
     @Override
-    public UMembership getMembership(final String groupKey) {
-        return IterableUtils.find(getMemberships(), new Predicate<UMembership>() {
-
-            @Override
-            public boolean evaluate(final UMembership membership) {
-                return groupKey != null && groupKey.equals(membership.getRightEnd().getKey());
-            }
-        });
-    }
-
-    @Override
     public List<? extends UMembership> getMemberships() {
         return memberships;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
index fb28c4e..37e227f 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AnyValidator.java
@@ -18,42 +18,63 @@
  */
 package org.apache.syncope.core.persistence.jpa.validation.entity;
 
-import java.util.Collection;
 import javax.validation.ConstraintValidatorContext;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
 import org.apache.syncope.common.lib.types.EntityViolationType;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.conf.Conf;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory;
 
 @SuppressWarnings("rawtypes")
 public class AnyValidator extends AbstractValidator<AnyCheck, Any> {
 
+    private boolean raiseNotAllowedViolation(
+            final ConstraintValidatorContext context,
+            final String schema,
+            final Group group) {
+
+        if (group == null) {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidPlainAttr,
+                            schema + " not allowed for this instance")).
+                    addPropertyNode("plainAttrs").addConstraintViolation();
+        } else {
+            context.buildConstraintViolationWithTemplate(
+                    getTemplate(EntityViolationType.InvalidPlainAttr,
+                            schema + " not allowed for membership of group " + group.getName())).
+                    addPropertyNode("plainAttrs").addConstraintViolation();
+        }
+        return false;
+    }
+
     @Override
     public boolean isValid(final Any any, final ConstraintValidatorContext context) {
         context.disableDefaultConstraintViolation();
 
         if (!(any instanceof Conf)) {
-            Collection<String> allowedPlainSchemas = CollectionUtils.collect(new JPAAnyUtilsFactory().
-                    getInstance(any.getType().getKind()).getAllowedSchemas(any, PlainSchema.class),
-                    new Transformer<PlainSchema, String>() {
+            AllowedSchemas<PlainSchema> allowedPlainSchemas = new JPAAnyUtilsFactory().
+                    getInstance(any.getType().getKind()).getAllowedSchemas(any, PlainSchema.class);
 
-                @Override
-                public String transform(final PlainSchema schema) {
-                    return schema.getKey();
+            for (PlainAttr<?> attr : ((Any<?>) any).getPlainAttrs()) {
+                if (attr != null && !allowedPlainSchemas.forSelfContains(attr.getSchema().getKey())) {
+                    return raiseNotAllowedViolation(context, attr.getSchema().getKey(), null);
                 }
-            });
+            }
+            if (any instanceof GroupableRelatable) {
+                for (Membership<?> membership : ((GroupableRelatable<?, ?, ?, ?, ?>) any).getMemberships()) {
+                    for (PlainAttr<?> attr : ((GroupableRelatable<?, ?, ?, ?, ?>) any).getPlainAttrs(membership)) {
+                        if (attr != null && !allowedPlainSchemas.forMembershipsContains(
+                                membership.getRightEnd(), attr.getSchema().getKey())) {
 
-            for (PlainAttr<?> attr : ((Any<?>) any).getPlainAttrs()) {
-                if (attr != null && !allowedPlainSchemas.contains(attr.getSchema().getKey())) {
-                    context.buildConstraintViolationWithTemplate(
-                            getTemplate(EntityViolationType.InvalidPlainSchema,
-                                    attr.getSchema().getKey() + " not allowed for this instance")).
-                            addPropertyNode("plainAttrs").addConstraintViolation();
-                    return false;
+                            return raiseNotAllowedViolation(
+                                    context, attr.getSchema().getKey(), membership.getRightEnd());
+                        }
+                    }
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
index 387e368..e1bdf68 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java
@@ -29,6 +29,7 @@ import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.entity.AnnotatedEntity;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.Entity;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 import org.apache.syncope.core.persistence.api.entity.Policy;
 import org.apache.syncope.core.persistence.api.entity.ProvidedKeyEntity;
 import org.apache.syncope.core.persistence.api.entity.Schema;
@@ -41,9 +42,6 @@ import org.slf4j.LoggerFactory;
  */
 public class EntityValidationListener {
 
-    /**
-     * Logger.
-     */
     private static final Logger LOG = LoggerFactory.getLogger(EntityValidationListener.class);
 
     @PrePersist
@@ -62,6 +60,7 @@ public class EntityValidationListener {
                         && !Schema.class.equals(interf)
                         && !Task.class.equals(interf)
                         && !Policy.class.equals(interf)
+                        && !GroupableRelatable.class.equals(interf)
                         && !Any.class.equals(interf)
                         && Entity.class.isAssignableFrom(interf)) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
index da00ebd..64ec693 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java
@@ -74,7 +74,7 @@ public class PlainAttrValueValidator extends AbstractValidator<PlainAttrValueChe
                             + "]" + " is " + uniqueValueSchema + ", while owning attribute schema is " + attrSchema);
 
                     context.disableDefaultConstraintViolation();
-                    context.buildConstraintViolationWithTemplate(getTemplate(EntityViolationType.InvalidPlainSchema,
+                    context.buildConstraintViolationWithTemplate(getTemplate(EntityViolationType.InvalidPlainAttr,
                             "Unique value schema is " + uniqueValueSchema
                             + ", while owning attribute schema is " + attrSchema)).addPropertyNode("schema").
                             addConstraintViolation();

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
index f12e913..cc324c6 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/AnyObjectTest.java
@@ -62,6 +62,7 @@ public class AnyObjectTest extends AbstractTest {
     @Test
     public void save() {
         AnyObject anyObject = entityFactory.newEntity(AnyObject.class);
+        anyObject.setName("a name");
         anyObject.setType(anyTypeDAO.find("PRINTER"));
         anyObject.setRealm(realmDAO.findByFullPath(SyncopeConstants.ROOT_REALM));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
index 712aa51..2b7f441 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainAttrTest.java
@@ -170,7 +170,7 @@ public class PlainAttrTest extends AbstractTest {
         // for attribute
         assertTrue(iee.hasViolation(EntityViolationType.InvalidValueList));
         // for uauv
-        assertTrue(iee.hasViolation(EntityViolationType.InvalidPlainSchema));
+        assertTrue(iee.hasViolation(EntityViolationType.InvalidPlainAttr));
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
new file mode 100644
index 0000000..f9bcff1
--- /dev/null
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/ConfTest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.jpa.outer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.syncope.core.persistence.api.dao.ConfDAO;
+import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
+import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
+import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr;
+import org.apache.syncope.core.persistence.jpa.AbstractTest;
+import org.apache.syncope.core.persistence.jpa.entity.conf.JPACPlainAttrValue;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional("Master")
+public class ConfTest extends AbstractTest {
+
+    @Autowired
+    private ConfDAO confDAO;
+
+    @Autowired
+    private PlainSchemaDAO plainSchemaDAO;
+
+    private void add(final CPlainAttr newAttr, final String value) {
+        JPACPlainAttrValue attrValue;
+        if (newAttr.getSchema().isUniqueConstraint()) {
+            attrValue = new JPACPlainAttrValue();
+            ((PlainAttrUniqueValue) attrValue).setSchema(newAttr.getSchema());
+        } else {
+            attrValue = new JPACPlainAttrValue();
+        }
+        newAttr.add(value, attrValue);
+    }
+
+    @Test
+    public void update() {
+        CPlainAttr expireTime = confDAO.find("token.expireTime");
+        assertNotNull(expireTime);
+        long value = expireTime.getValues().get(0).getLongValue();
+        value++;
+
+        CPlainAttr attr = entityFactory.newEntity(CPlainAttr.class);
+        attr.setSchema(plainSchemaDAO.find("token.expireTime"));
+        add(attr, String.valueOf(value));
+
+        confDAO.save(expireTime);
+        confDAO.flush();
+
+        CPlainAttr actual = confDAO.find("token.expireTime");
+        assertEquals(expireTime, actual);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
index ae450aa..8037a2b 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/GroupTest.java
@@ -271,6 +271,7 @@ public class GroupTest extends AbstractTest {
     public void adynMembership() {
         // 0. create any object matching the condition below
         AnyObject anyObject = entityFactory.newEntity(AnyObject.class);
+        anyObject.setName("name");
         anyObject.setType(anyTypeDAO.find("PRINTER"));
         anyObject.setRealm(realmDAO.findByFullPath("/even/two"));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
index 1a5a62d..cdb3067 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/UserTest.java
@@ -23,9 +23,14 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.util.List;
 import java.util.UUID;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
@@ -145,7 +150,91 @@ public class UserTest extends AbstractTest {
                 user.getRelationships().get(0).getRightEnd().getKey());
     }
 
-    @Test // search by derived attribute
+    @Test
+    public void membershipWithAttrs() {
+        User user = userDAO.findByUsername("vivaldi");
+        assertNotNull(user);
+        assertTrue(user.getMemberships().isEmpty());
+
+        // add 'obscure' to user (no membership): works because 'obscure' is from 'other', default class for USER
+        UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
+        attr.setOwner(user);
+        attr.setSchema(plainSchemaDAO.find("obscure"));
+        attr.add("testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+        user.add(attr);
+
+        // add 'obscure' to user (via 'artDirector' membership): does not work because 'obscure' is from 'other'
+        // but 'artDirector' defines no type extension
+        UMembership membership = entityFactory.newEntity(UMembership.class);
+        membership.setLeftEnd(user);
+        membership.setRightEnd(groupDAO.findByName("artDirector"));
+        user.add(membership);
+
+        attr = entityFactory.newEntity(UPlainAttr.class);
+        attr.setOwner(user);
+        attr.setMembership(membership);
+        attr.setSchema(plainSchemaDAO.find("obscure"));
+        attr.add("testvalue2", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+        user.add(attr);
+
+        try {
+            userDAO.save(user);
+            fail();
+        } catch (InvalidEntityException e) {
+            assertNotNull(e);
+        }
+
+        // replace 'artDirector' with 'additional', which defines type extension with class 'other' and 'csv':
+        // now it works
+        membership = user.getMembership(groupDAO.findByName("artDirector").getKey());
+        user.remove(user.getPlainAttr("obscure", membership));
+        user.getMemberships().remove(membership);
+        membership.setLeftEnd(null);
+
+        membership = entityFactory.newEntity(UMembership.class);
+        membership.setLeftEnd(user);
+        membership.setRightEnd(groupDAO.findByName("additional"));
+        user.add(membership);
+
+        attr = entityFactory.newEntity(UPlainAttr.class);
+        attr.setOwner(user);
+        attr.setMembership(membership);
+        attr.setSchema(plainSchemaDAO.find("obscure"));
+        attr.add("testvalue2", anyUtilsFactory.getInstance(AnyTypeKind.USER));
+        user.add(attr);
+
+        userDAO.save(user);
+        userDAO.flush();
+
+        user = userDAO.findByUsername("vivaldi");
+        assertEquals(1, user.getMemberships().size());
+
+        final UMembership newM = user.getMembership(groupDAO.findByName("additional").getKey());
+        assertEquals(1, user.getPlainAttrs(newM).size());
+
+        assertNull(user.getPlainAttr("obscure").getMembership());
+        assertEquals(2, user.getPlainAttrs("obscure").size());
+        assertTrue(user.getPlainAttrs("obscure").contains(user.getPlainAttr("obscure")));
+        assertTrue(IterableUtils.matchesAny(user.getPlainAttrs("obscure"), new Predicate<UPlainAttr>() {
+
+            @Override
+            public boolean evaluate(final UPlainAttr object) {
+                return object.getMembership() == null;
+            }
+        }));
+        assertTrue(IterableUtils.matchesAny(user.getPlainAttrs("obscure"), new Predicate<UPlainAttr>() {
+
+            @Override
+            public boolean evaluate(final UPlainAttr object) {
+                return newM.equals(object.getMembership());
+            }
+        }));
+    }
+
+    /**
+     * Search by derived attribute.
+     */
+    @Test
     public void issueSYNCOPE800() {
         // create derived attribute (literal as prefix)
         DerSchema prefix = entityFactory.newEntity(DerSchema.class);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 37fc8a1..e956a90 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -175,15 +175,15 @@ under the License.
          accountPolicy_id="20ab5a8c-4b0c-432c-b957-f7fb9784d9f7"
          passwordPolicy_id="ce93fcda-dc3a-4369-a7b0-a6108c261c85"/>
   
-  <AnyObject id="fc6dbc3a-6c07-4965-8781-921e7401a4a5"
+  <AnyObject id="fc6dbc3a-6c07-4965-8781-921e7401a4a5" name="HP LJ 1300n"
              realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" type_id="PRINTER"
              creator="admin" lastModifier="admin" 
              creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
-  <AnyObject id="8559d14d-58c2-46eb-a2d4-a7d35161e8f8"
+  <AnyObject id="8559d14d-58c2-46eb-a2d4-a7d35161e8f8" name="Canon MF 8030cn"
              realm_id="e4c28e7a-9dbf-4ee7-9441-93812a0d4a28" type_id="PRINTER"
              creator="admin" lastModifier="admin" 
              creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
-  <AnyObject id="9e1d130c-d6a3-48b1-98b3-182477ed0688"
+  <AnyObject id="9e1d130c-d6a3-48b1-98b3-182477ed0688" name="Epson Stylus Color"
              realm_id="0679e069-7355-4b20-bd11-a5a0a5453c7c" type_id="PRINTER"
              creator="admin" lastModifier="admin" 
              creationDate="2010-10-20 11:00:00" lastChangeDate="2010-10-20 11:00:00"/>
@@ -966,6 +966,9 @@ under the License.
   <MappingItem id="23aa0299-ddbb-4e59-8918-0ab2a32465fa" mapping_id="16439b5f-50c3-4604-97e9-f4004933abd8" extAttrName="ID" 
                intMappingType="AnyObjectKey" mandatoryCondition="true"
                connObjectKey="1" password="0" purpose="BOTH"/>
+  <MappingItem id="3dc96af0-5d0a-4ec1-be84-244716d88401" mapping_id="16439b5f-50c3-4604-97e9-f4004933abd8" extAttrName="PRINTERNAME" 
+               intMappingType="AnyObjectName" mandatoryCondition="true"
+               connObjectKey="0" password="0" purpose="BOTH"/>
   <MappingItem id="f3ef9f8b-e667-4b18-969f-ba98c3d78bc0" mapping_id="16439b5f-50c3-4604-97e9-f4004933abd8" extAttrName="LOCATION" 
                intAttrName="location" intMappingType="AnyObjectPlainSchema"
                mandatoryCondition="false" connObjectKey="0" password="0" purpose="BOTH"/>
@@ -985,7 +988,7 @@ under the License.
         pullMode="INCREMENTAL" unmatchingRule="ASSIGN" matchingRule="UPDATE" active="1"/>
   <AnyTemplatePullTask id="3a6173a9-8c34-4e37-b3b1-0c2ea385fac0"
                        pullTask_id="c41b9b71-9bfa-4f90-89f2-84787def4c5c" anyType_id="USER"
-                       template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":["csv"],"derAttrs":[{"schema":"cn","readonly":false,"values":[""]}],"virAttrs":[],"resources":["resource-testdb"],"relationships":[],"memberships":[{"leftType":null,"leftKey":0,"rightType":"GROUP","rightKey":"f779c0d4-633b-4be5-8f57-32eb478a3ca5","groupName":null}],"dynGroups":[],"roles":[],"dynRoles":[],"plainAttrs":[{"schema":"ctype","readonly":false,"values":["email == &apos;test8@syncope.apache.org&apos;? &apos;TYPE_8&apos;: &apos;TYPE_OTHER&apos;"]}]}'/>
+                       template='{"@class":"org.apache.syncope.common.lib.to.UserTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"USER","realm":null,"status":null,"password":null,"token":null,"tokenExpireTime":null,"username":null,"lastLoginDate":null,"changePwdDate":null,"failedLogins":null,"securityQuestion":null,"securityAnswer":null,"auxClasses":["csv"],"derAttrs":[{"schema":"cn","readonly":false,"values":[""]}],"virAttrs":[],"resources":["resource-testdb"],"relationships":[],"memberships":[{"rightType":"GROUP","rightKey":"f779c0d4-633b-4be5-8f57-32eb478a3ca5","groupName":null}],"dynGroups":[],"roles":[],"dynRoles":[],"plainAttrs":[{"schema":"ctype","readonly":false,"values":["email == &apos;test8@syncope.apache.org&apos;? &apos;TYPE_8&apos;: &apos;TYPE_OTHER&apos;"]}]}'/>
   <AnyTemplatePullTask id="b3772d66-ec06-4133-bf38-b3273845ac5b"
                        pullTask_id="c41b9b71-9bfa-4f90-89f2-84787def4c5c" anyType_id="GROUP"
                        template='{"@class":"org.apache.syncope.common.lib.to.GroupTO","creator":null,"creationDate":null,"lastModifier":null,"lastChangeDate":null,"key":null,"type":"GROUP","realm":null,"status":null,"name":null,"userOwner":null,"groupOwner":null,"udynMembershipCond":null,"auxClasses":[],"derAttrs":[],"virAttrs":[],"resources":[],"plainAttrs":[]}'/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
index bc70fb8..c4f44bd 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.provisioning.api;
 import java.util.Map;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 
 public interface DerAttrHandler {
 
@@ -37,7 +38,27 @@ public interface DerAttrHandler {
      * Calculates derived attributes values associated to the given any.
      *
      * @param any any object
-     * @return derived attribute values, either for local cache or external resources
+     * @return derived attribute values
      */
     Map<DerSchema, String> getValues(Any<?> any);
+
+    /**
+     * Calculates derived attribute value associated to the given any, for the given membership and
+     * derived schema.
+     *
+     * @param any any object
+     * @param membership membership
+     * @param schema derived schema
+     * @return derived attribute value
+     */
+    String getValue(Any<?> any, Membership<?> membership, DerSchema schema);
+
+    /**
+     * Calculates derived attributes values associated to the given any, for the given membership.
+     *
+     * @param any any object
+     * @param membership membership
+     * @return derived attribute values
+     */
+    Map<DerSchema, String> getValues(final Any<?> any, final Membership<?> membership);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
----------------------------------------------------------------------
diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
index 0b8d60f..72bb198 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/VirAttrHandler.java
@@ -21,13 +21,14 @@ package org.apache.syncope.core.provisioning.api;
 import java.util.List;
 import java.util.Map;
 import org.apache.syncope.core.persistence.api.entity.Any;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 
 public interface VirAttrHandler {
 
     /**
      * Query external resource (or cache, if configured) associated to the given any for values associated to the given
-     * virtual schema.
+     * virtual schema, not related to any membership.
      *
      * @param any any object
      * @param schema virtual schema
@@ -37,13 +38,36 @@ public interface VirAttrHandler {
     List<String> getValues(Any<?> any, VirSchema schema);
 
     /**
+     * Query external resource (or cache, if configured) associated to the given any for values associated to the given
+     * virtual schema, for the given membership.
+     *
+     * @param any any object
+     * @param membership membership
+     * @param schema virtual schema
+     * @return virtual attribute values, either for local cache or external resource, if resource is owned by the given
+     * any and associated to the given virtual schema; empty list otherwise.
+     */
+    List<String> getValues(Any<?> any, Membership<?> membership, VirSchema schema);
+
+    /**
      * Query external resources (or cache, if configured) associated to the given any for values associated to all
      * {@link VirSchema} instances in the {@link org.apache.syncope.core.persistence.api.entity.AnyTypeClass}
-     * associated to the given any.
+     * associated to the given any, with no membership.
      *
      * @param any any object
      * @return virtual attribute values, either for local cache or external resources
      */
     Map<VirSchema, List<String>> getValues(Any<?> any);
 
+    /**
+     * Query external resources (or cache, if configured) associated to the given any for values associated to all
+     * {@link VirSchema} instances in the {@link org.apache.syncope.core.persistence.api.entity.AnyTypeClass}
+     * associated to the given any, for the given membership.
+     *
+     * @param any any object
+     * @param membership membership
+     * @return virtual attribute values, either for local cache or external resources
+     */
+    Map<VirSchema, List<String>> getValues(Any<?> any, Membership<?> membership);
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DerAttrHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DerAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DerAttrHandlerImpl.java
index f827f46..0261752 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DerAttrHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DerAttrHandlerImpl.java
@@ -28,6 +28,7 @@ import org.apache.syncope.core.provisioning.java.jexl.JexlUtils;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
 import org.apache.syncope.core.persistence.api.entity.DerSchema;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.provisioning.api.DerAttrHandler;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,6 +36,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
+@Transactional(readOnly = true)
 @Component
 public class DerAttrHandlerImpl implements DerAttrHandler {
 
@@ -57,10 +59,23 @@ public class DerAttrHandlerImpl implements DerAttrHandler {
         return result;
     }
 
-    @Transactional(readOnly = true)
     @Override
     public String getValue(final Any<?> any, final DerSchema schema) {
-        if (!anyUtilsFactory.getInstance(any).getAllowedSchemas(any, DerSchema.class).contains(schema)) {
+        if (!anyUtilsFactory.getInstance(any).
+                getAllowedSchemas(any, DerSchema.class).forSelfContains(schema)) {
+
+            LOG.debug("{} not allowed for {}", schema, any);
+            return null;
+        }
+
+        return getValues(any, Collections.singleton(schema)).get(schema);
+    }
+
+    @Override
+    public String getValue(final Any<?> any, final Membership<?> membership, final DerSchema schema) {
+        if (!anyUtilsFactory.getInstance(any).
+                getAllowedSchemas(any, DerSchema.class).getForMembership(membership.getRightEnd()).contains(schema)) {
+
             LOG.debug("{} not allowed for {}", schema, any);
             return null;
         }
@@ -68,10 +83,19 @@ public class DerAttrHandlerImpl implements DerAttrHandler {
         return getValues(any, Collections.singleton(schema)).get(schema);
     }
 
-    @Transactional(readOnly = true)
     @Override
     public Map<DerSchema, String> getValues(final Any<?> any) {
-        return getValues(any, anyUtilsFactory.getInstance(any).getAllowedSchemas(any, DerSchema.class));
+        return getValues(
+                any,
+                anyUtilsFactory.getInstance(any).getAllowedSchemas(any, DerSchema.class).getForSelf());
+    }
+
+    @Override
+    public Map<DerSchema, String> getValues(final Any<?> any, final Membership<?> membership) {
+        return getValues(
+                any,
+                anyUtilsFactory.getInstance(any).getAllowedSchemas(any, DerSchema.class).
+                getForMembership(membership.getRightEnd()));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
index c742c1a..b84799a 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/MappingManagerImpl.java
@@ -32,6 +32,7 @@ import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.GroupTO;
@@ -68,6 +69,7 @@ import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
 import org.apache.syncope.core.persistence.api.entity.Schema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
+import org.apache.syncope.core.persistence.api.entity.anyobject.APlainAttrValue;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.persistence.api.entity.resource.Mapping;
 import org.apache.syncope.core.persistence.api.entity.resource.Provision;
@@ -698,6 +700,16 @@ public class MappingManagerImpl implements MappingManager {
                 }
                 break;
 
+            case AnyObjectName:
+                for (Any<?> any : anys) {
+                    if (any instanceof AnyObject) {
+                        APlainAttrValue attrValue = entityFactory.newEntity(APlainAttrValue.class);
+                        attrValue.setStringValue(((AnyObject) any).getName());
+                        values.add(attrValue);
+                    }
+                }
+                break;
+
             default:
         }
 
@@ -800,6 +812,14 @@ public class MappingManagerImpl implements MappingManager {
                 }
                 break;
 
+            case AnyObjectName:
+                if (anyTO instanceof AnyObjectTO) {
+                    ((AnyObjectTO) anyTO).setName(values.isEmpty() || values.get(0) == null
+                            ? null
+                            : values.get(0).toString());
+                }
+                break;
+
             case UserPlainSchema:
             case GroupPlainSchema:
             case AnyObjectPlainSchema:

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
----------------------------------------------------------------------
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
index b65cc79..67a821c 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/VirAttrHandlerImpl.java
@@ -29,6 +29,7 @@ import org.apache.commons.collections4.ListUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
+import org.apache.syncope.core.persistence.api.entity.Membership;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.resource.MappingItem;
@@ -48,6 +49,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
+@Transactional(readOnly = true)
 @Component
 public class VirAttrHandlerImpl implements VirAttrHandler {
 
@@ -122,7 +124,8 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
                             if (attr != null) {
                                 VirAttrCacheValue virAttrCacheValue = new VirAttrCacheValue();
                                 virAttrCacheValue.setValues(attr.getValue());
-                                virAttrCache.put(any.getType().getKey(), any.getKey(), schema.getKey(),
+                                virAttrCache.put(
+                                        any.getType().getKey(), any.getKey(), schema.getKey(),
                                         virAttrCacheValue);
                                 LOG.debug("Values for {} set in cache: {}", schema, virAttrCacheValue);
 
@@ -139,10 +142,23 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
         return result;
     }
 
-    @Transactional(readOnly = true)
     @Override
     public List<String> getValues(final Any<?> any, final VirSchema schema) {
-        if (!anyUtilsFactory.getInstance(any).getAllowedSchemas(any, VirSchema.class).contains(schema)) {
+        if (!anyUtilsFactory.getInstance(any).
+                getAllowedSchemas(any, VirSchema.class).forSelfContains(schema)) {
+
+            LOG.debug("{} not allowed for {}", schema, any);
+            return Collections.emptyList();
+        }
+
+        return ListUtils.emptyIfNull(getValues(any, Collections.singleton(schema)).get(schema));
+    }
+
+    @Override
+    public List<String> getValues(final Any<?> any, final Membership<?> membership, final VirSchema schema) {
+        if (!anyUtilsFactory.getInstance(any).
+                getAllowedSchemas(any, VirSchema.class).getForMembership(membership.getRightEnd()).contains(schema)) {
+
             LOG.debug("{} not allowed for {}", schema, any);
             return Collections.emptyList();
         }
@@ -150,9 +166,19 @@ public class VirAttrHandlerImpl implements VirAttrHandler {
         return ListUtils.emptyIfNull(getValues(any, Collections.singleton(schema)).get(schema));
     }
 
-    @Transactional(readOnly = true)
     @Override
     public Map<VirSchema, List<String>> getValues(final Any<?> any) {
-        return getValues(any, anyUtilsFactory.getInstance(any).getAllowedSchemas(any, VirSchema.class));
+        return getValues(
+                any,
+                anyUtilsFactory.getInstance(any).getAllowedSchemas(any, VirSchema.class).getForSelf());
     }
+
+    @Override
+    public Map<VirSchema, List<String>> getValues(final Any<?> any, final Membership<?> membership) {
+        return getValues(
+                any,
+                anyUtilsFactory.getInstance(any).getAllowedSchemas(any, VirSchema.class).
+                getForMembership(membership.getRightEnd()));
+    }
+
 }


[6/6] syncope git commit: [SYNCOPE-862] Preliminary work

Posted by il...@apache.org.
[SYNCOPE-862] Preliminary work


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

Branch: refs/heads/SYNCOPE-862
Commit: f0ef4df28cf75e104a41cf679a8c29b14badd299
Parents: a7ef4e1
Author: Francesco Chicchiricc� <il...@apache.org>
Authored: Tue May 31 17:59:00 2016 +0200
Committer: Francesco Chicchiricc� <il...@apache.org>
Committed: Wed Jun 1 12:14:17 2016 +0200

----------------------------------------------------------------------
 .../AnyObjectDisplayAttributesModalPanel.java   |   2 +-
 .../panels/ConnObjectDirectoryPanel.java        |   8 +-
 .../html/repeater/data/table/AttrColumn.java    |  19 +-
 .../data/table/ConnObjectAttrColumn.java        |  63 +++++
 .../console/wizards/any/ConnObjectPanel.java    |   4 +-
 .../client/console/wizards/any/Groups.java      |   1 -
 .../wizards/resources/ResourceMappingPanel.java |   1 +
 .../syncope/common/lib/AnyOperations.java       |  90 +++++--
 .../common/lib/patch/AnyObjectPatch.java        |  10 +
 .../syncope/common/lib/patch/AnyPatch.java      |  10 +-
 .../common/lib/patch/AttributablePatch.java     |  38 +++
 .../common/lib/patch/MembershipPatch.java       |  33 ++-
 .../syncope/common/lib/to/AnyObjectTO.java      |  10 +
 .../org/apache/syncope/common/lib/to/AnyTO.java |  34 ++-
 .../syncope/common/lib/to/AttributableTO.java   |  53 ++++
 .../syncope/common/lib/to/ConnObjectTO.java     |   9 +-
 .../syncope/common/lib/to/MembershipTO.java     |  75 +++++-
 .../syncope/common/lib/to/RelationshipTO.java   |  26 --
 .../common/lib/types/EntityViolationType.java   |   4 +-
 .../common/lib/types/IntMappingType.java        |   8 +-
 .../persistence/api/dao/AllowedSchemas.java     | 114 +++++++++
 .../core/persistence/api/dao/AnyDAO.java        |   3 +-
 .../core/persistence/api/dao/AnyObjectDAO.java  |   4 +
 .../core/persistence/api/entity/Any.java        |   2 +
 .../core/persistence/api/entity/AnyUtils.java   |   3 +-
 .../api/entity/GroupablePlainAttr.java          |  26 ++
 .../api/entity/GroupableRelatable.java          | 100 ++++++++
 .../api/entity/anyobject/APlainAttr.java        |   4 +-
 .../api/entity/anyobject/AnyObject.java         |  24 +-
 .../persistence/api/entity/user/UPlainAttr.java |   4 +-
 .../core/persistence/api/entity/user/User.java  |  32 +--
 .../persistence/jpa/dao/AbstractAnyDAO.java     |  56 +++--
 .../persistence/jpa/dao/JPAAnyObjectDAO.java    |  34 +++
 .../core/persistence/jpa/dao/JPAConfDAO.java    |  12 +-
 .../core/persistence/jpa/dao/JPAGroupDAO.java   |  32 ++-
 .../persistence/jpa/dao/JPAPlainAttrDAO.java    |   2 +-
 .../persistence/jpa/entity/AbstractAny.java     |  28 ---
 .../jpa/entity/AbstractGroupableRelatable.java  | 158 ++++++++++++
 .../persistence/jpa/entity/JPAAnyUtils.java     |  13 +-
 .../jpa/entity/anyobject/JPAAPlainAttr.java     |  22 +-
 .../jpa/entity/anyobject/JPAAnyObject.java      |  95 +++----
 .../persistence/jpa/entity/conf/JPAConf.java    |   8 +-
 .../jpa/entity/group/JPAGPlainAttr.java         |   4 +-
 .../persistence/jpa/entity/group/JPAGroup.java  |  45 +++-
 .../jpa/entity/resource/JPAMappingItem.java     |   4 +
 .../jpa/entity/user/JPAUPlainAttr.java          |  22 +-
 .../persistence/jpa/entity/user/JPAUser.java    |  73 ++----
 .../jpa/validation/entity/AnyValidator.java     |  55 ++--
 .../entity/EntityValidationListener.java        |   5 +-
 .../entity/PlainAttrValueValidator.java         |   2 +-
 .../persistence/jpa/inner/AnyObjectTest.java    |   1 +
 .../persistence/jpa/inner/PlainAttrTest.java    |   2 +-
 .../core/persistence/jpa/outer/ConfTest.java    |  72 ++++++
 .../core/persistence/jpa/outer/GroupTest.java   |   1 +
 .../core/persistence/jpa/outer/UserTest.java    |  91 ++++++-
 .../test/resources/domains/MasterContent.xml    |  11 +-
 .../core/provisioning/api/DerAttrHandler.java   |  23 +-
 .../core/provisioning/api/VirAttrHandler.java   |  28 ++-
 .../provisioning/java/DerAttrHandlerImpl.java   |  32 ++-
 .../provisioning/java/MappingManagerImpl.java   |  20 ++
 .../provisioning/java/VirAttrHandlerImpl.java   |  36 ++-
 .../java/data/AbstractAnyDataBinder.java        | 248 ++++++++++++-------
 .../java/data/AnyObjectDataBinderImpl.java      | 115 +++++++--
 .../java/data/GroupDataBinderImpl.java          |   6 +-
 .../java/data/UserDataBinderImpl.java           |  90 +++++--
 .../java/job/SetUMembershipsJob.java            |   3 +-
 .../provisioning/java/pushpull/PullUtils.java   |   8 +
 .../java/utils/ConnObjectUtils.java             |   2 +-
 .../activiti/ActivitiUserWorkflowAdapter.java   |   2 +-
 fit/build-tools/src/main/resources/testdb.sql   |   1 +
 .../syncope/fit/console/AnyObjectsITCase.java   |   6 +-
 .../syncope/fit/console/BulkActionITCase.java   |   2 +-
 .../fit/console/DisplayAttributesITCase.java    |   4 +-
 .../syncope/fit/core/AnyObjectITCase.java       |   1 +
 .../syncope/fit/core/AuthenticationITCase.java  |   1 +
 .../syncope/fit/core/CamelRouteITCase.java      |   6 +-
 .../syncope/fit/core/MembershipITCase.java      | 162 ++++++++++++
 .../org/apache/syncope/fit/core/UserITCase.java |  13 +-
 .../apache/syncope/fit/core/UserSelfITCase.java |   3 +-
 .../resources/scriptedsql/CreateScript.groovy   |   3 +-
 .../resources/scriptedsql/SchemaScript.groovy   |   1 +
 .../resources/scriptedsql/SearchScript.groovy   |   2 +-
 .../resources/scriptedsql/SyncScript.groovy     |   3 +-
 .../resources/scriptedsql/TestScript.groovy     |   2 +-
 .../resources/scriptedsql/UpdateScript.groovy   |   7 +-
 85 files changed, 1945 insertions(+), 547 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
index b99a323..39f30ad 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectDisplayAttributesModalPanel.java
@@ -35,7 +35,7 @@ public class AnyObjectDisplayAttributesModalPanel<T extends Serializable> extend
 
     private static final long serialVersionUID = 5194630813773543054L;
 
-    public static final String[] DEFAULT_SELECTION = { "key" };
+    public static final String[] DEFAULT_SELECTION = { "key", "name" };
 
     public AnyObjectDisplayAttributesModalPanel(
             final BaseModal<T> modal,

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
index 99dde2e..d80130b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
@@ -30,7 +30,7 @@ import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 import org.apache.syncope.client.console.panels.ConnObjectDirectoryPanel.ConnObjectDataProvider;
 import org.apache.syncope.client.console.rest.ResourceRestClient;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
-import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.AttrColumn;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ConnObjectAttrColumn;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
@@ -101,9 +101,9 @@ public abstract class ConnObjectDirectoryPanel
     protected List<IColumn<ConnObjectTO, String>> getColumns() {
         final List<IColumn<ConnObjectTO, String>> columns = new ArrayList<>();
 
-        columns.add(new AttrColumn<>(ConnIdSpecialAttributeName.UID, SchemaType.PLAIN));
-        columns.add(new AttrColumn<>(ConnIdSpecialAttributeName.NAME, SchemaType.PLAIN));
-        columns.add(new AttrColumn<>(ConnIdSpecialAttributeName.ENABLE, SchemaType.PLAIN));
+        columns.add(new ConnObjectAttrColumn(ConnIdSpecialAttributeName.UID, SchemaType.PLAIN));
+        columns.add(new ConnObjectAttrColumn(ConnIdSpecialAttributeName.NAME, SchemaType.PLAIN));
+        columns.add(new ConnObjectAttrColumn(ConnIdSpecialAttributeName.ENABLE, SchemaType.PLAIN));
 
         columns.add(new ActionColumn<ConnObjectTO, String>(new ResourceModel("actions")) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
index 9a90ef6..b756a05 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
@@ -26,10 +26,9 @@ import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.repeater.Item;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.ResourceModel;
-import org.apache.syncope.common.lib.to.AnyTO;
-import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.AttributableTO;
 
-public class AttrColumn<T extends ConnObjectTO> extends AbstractColumn<T, String> {
+public class AttrColumn<T extends AttributableTO> extends AbstractColumn<T, String> {
 
     private static final long serialVersionUID = 2624734332447371372L;
 
@@ -59,20 +58,14 @@ public class AttrColumn<T extends ConnObjectTO> extends AbstractColumn<T, String
                 break;
 
             case DERIVED:
-                if (rowModel.getObject() instanceof AnyTO) {
-                    AnyTO obj = AnyTO.class.cast(rowModel.getObject());
-                    if (obj.getDerAttrMap().containsKey(name)) {
-                        values = obj.getDerAttrMap().get(name).getValues();
-                    }
+                if (rowModel.getObject().getDerAttrMap().containsKey(name)) {
+                    values = rowModel.getObject().getDerAttrMap().get(name).getValues();
                 }
                 break;
 
             case VIRTUAL:
-                if (rowModel.getObject() instanceof AnyTO) {
-                    AnyTO obj = AnyTO.class.cast(rowModel.getObject());
-                    if (obj.getVirAttrMap().containsKey(name)) {
-                        values = obj.getVirAttrMap().get(name).getValues();
-                    }
+                if (rowModel.getObject().getVirAttrMap().containsKey(name)) {
+                    values = rowModel.getObject().getVirAttrMap().get(name).getValues();
                 }
                 break;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java
new file mode 100644
index 0000000..56ead58
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ConnObjectAttrColumn.java
@@ -0,0 +1,63 @@
+/*
+ * 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.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.List;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+
+public class ConnObjectAttrColumn extends AbstractColumn<ConnObjectTO, String> {
+
+    private static final long serialVersionUID = 2624734332447371372L;
+
+    private final String name;
+
+    public ConnObjectAttrColumn(final String name, final SchemaType schemaType) {
+        // set sortProperty to schematype#name (e.g. derivedSchema#cn, 
+        // for use with SortableUserProviderComparator.AttrModel#getObject)
+        super(new ResourceModel(name, name), schemaType.name() + "#" + name);
+        this.name = name;
+    }
+
+    @Override
+    public void populateItem(
+            final Item<ICellPopulator<ConnObjectTO>> cellItem,
+            final String componentId,
+            final IModel<ConnObjectTO> rowModel) {
+
+        List<String> values = null;
+        if (rowModel.getObject().getPlainAttrMap().containsKey(name)) {
+            values = rowModel.getObject().getPlainAttrMap().get(name).getValues();
+        }
+
+        if (values == null || values.isEmpty()) {
+            cellItem.add(new Label(componentId, ""));
+        } else if (values.size() == 1) {
+            cellItem.add(new Label(componentId, values.get(0)));
+        } else {
+            cellItem.add(new Label(componentId, values.toString()));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
index 14e3e33..49f6801 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/ConnObjectPanel.java
@@ -57,7 +57,7 @@ public class ConnObjectPanel extends Panel {
             protected List<AttrTO> load() {
                 List<AttrTO> attrs = new ArrayList<>(connObjectTOs == null || connObjectTOs.getRight() == null
                         ? Collections.<AttrTO>emptyList()
-                        : connObjectTOs.getRight().getPlainAttrs());
+                        : connObjectTOs.getRight().getAttrs());
 
                 Collections.sort(attrs, new Comparator<AttrTO>() {
 
@@ -77,7 +77,7 @@ public class ConnObjectPanel extends Panel {
             }
         };
 
-        final Map<String, AttrTO> beforeProfile = connObjectTOs.getLeft() == null
+        final Map<String, AttrTO> beforeProfile = connObjectTOs == null || connObjectTOs.getLeft() == null
                 ? null
                 : connObjectTOs.getLeft().getPlainAttrMap();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
index 8c84cda..401f8e0 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Groups.java
@@ -105,7 +105,6 @@ public class Groups extends WizardStep {
                     public MembershipTO transform(final GroupTO input) {
                         return new MembershipTO.Builder().
                                 group(input.getKey(), input.getName()).
-                                left(anyTO.getKey(), anyTO.getType()).
                                 build();
                     }
                 }, new ArrayList<MembershipTO>());

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
index 5020bd7..06ea7c8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java
@@ -570,6 +570,7 @@ public class ResourceMappingPanel extends Panel {
                 case GroupKey:
                 case GroupName:
                 case AnyObjectKey:
+                case AnyObjectName:
                 default:
                     toBeUpdated.setRequired(false);
                     toBeUpdated.setEnabled(false);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
index 39fbc63..1f985a4 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/AnyOperations.java
@@ -25,6 +25,7 @@ import java.util.Set;
 import org.apache.commons.collections4.Closure;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
@@ -173,7 +174,10 @@ public final class AnyOperations {
 
         diff(updated, original, result, incremental);
 
-        // 1. relationships
+        // 1. name
+        result.setName(replacePatchItem(updated.getName(), original.getName(), new StringReplacePatchItem()));
+
+        // 2. relationships
         Map<Pair<String, String>, RelationshipTO> updatedRels = updated.getRelationshipMap();
         Map<Pair<String, String>, RelationshipTO> originalRels = original.getRelationshipMap();
 
@@ -193,21 +197,21 @@ public final class AnyOperations {
             }
         }
 
-        // 2. memberships
+        // 3. memberships
         Map<String, MembershipTO> updatedMembs = updated.getMembershipMap();
         Map<String, MembershipTO> originalMembs = original.getMembershipMap();
 
         for (Map.Entry<String, MembershipTO> entry : updatedMembs.entrySet()) {
             if (!originalMembs.containsKey(entry.getKey())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.ADD_REPLACE).membershipTO(entry.getValue()).build());
+                        operation(PatchOperation.ADD_REPLACE).group(entry.getValue().getGroupKey()).build());
             }
         }
 
         if (!incremental) {
             for (String key : CollectionUtils.subtract(originalMembs.keySet(), updatedMembs.keySet())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.DELETE).membershipTO(originalMembs.get(key)).build());
+                        operation(PatchOperation.DELETE).group(originalMembs.get(key).getGroupKey()).build());
             }
         }
 
@@ -294,14 +298,14 @@ public final class AnyOperations {
         for (Map.Entry<String, MembershipTO> entry : updatedMembs.entrySet()) {
             if (!originalMembs.containsKey(entry.getKey())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.ADD_REPLACE).membershipTO(entry.getValue()).build());
+                        operation(PatchOperation.ADD_REPLACE).group(entry.getValue().getGroupKey()).build());
             }
         }
 
         if (!incremental) {
             for (String key : CollectionUtils.subtract(originalMembs.keySet(), updatedMembs.keySet())) {
                 result.getMemberships().add(new MembershipPatch.Builder().
-                        operation(PatchOperation.DELETE).membershipTO(originalMembs.get(key)).build());
+                        operation(PatchOperation.DELETE).group(originalMembs.get(key).getGroupKey()).build());
             }
         }
 
@@ -410,7 +414,7 @@ public final class AnyOperations {
 
         // 2. plain attributes
         result.getPlainAttrs().clear();
-        result.getPlainAttrs().addAll(AnyOperations.patch(to.getPlainAttrMap(), patch.getPlainAttrs()));
+        result.getPlainAttrs().addAll(patch(to.getPlainAttrMap(), patch.getPlainAttrs()));
 
         // 3. virtual attributes
         result.getVirAttrs().clear();
@@ -432,7 +436,7 @@ public final class AnyOperations {
 
     public static GroupTO patch(final GroupTO groupTO, final GroupPatch groupPatch) {
         GroupTO result = SerializationUtils.clone(groupTO);
-        AnyOperations.patch(groupTO, groupPatch, result);
+        patch(groupTO, groupPatch, result);
 
         if (groupPatch.getName() != null) {
             result.setName(groupPatch.getName().getValue());
@@ -454,10 +458,10 @@ public final class AnyOperations {
 
     public static AnyObjectTO patch(final AnyObjectTO anyObjectTO, final AnyObjectPatch anyObjectPatch) {
         AnyObjectTO result = SerializationUtils.clone(anyObjectTO);
-        AnyOperations.patch(anyObjectTO, anyObjectPatch, result);
+        patch(anyObjectTO, anyObjectPatch, result);
 
         // 1. relationships
-        for (final RelationshipPatch relPatch : anyObjectPatch.getRelationships()) {
+        for (RelationshipPatch relPatch : anyObjectPatch.getRelationships()) {
             if (relPatch.getRelationshipTO() == null) {
                 LOG.warn("Invalid {} specified: {}", RelationshipPatch.class.getName(), relPatch);
             } else {
@@ -470,12 +474,37 @@ public final class AnyOperations {
 
         // 2. memberships
         for (final MembershipPatch membPatch : anyObjectPatch.getMemberships()) {
-            if (membPatch.getMembershipTO() == null) {
+            if (membPatch.getGroup() == null) {
                 LOG.warn("Invalid {} specified: {}", MembershipPatch.class.getName(), membPatch);
             } else {
-                result.getMemberships().remove(membPatch.getMembershipTO());
+                MembershipTO memb = IterableUtils.find(result.getMemberships(), new Predicate<MembershipTO>() {
+
+                    @Override
+                    public boolean evaluate(final MembershipTO object) {
+                        return membPatch.getGroup().equals(object.getGroupKey());
+                    }
+                });
+                if (memb != null) {
+                    result.getMemberships().remove(memb);
+                }
+
                 if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
-                    result.getMemberships().add(membPatch.getMembershipTO());
+                    MembershipTO newMembershipTO = new MembershipTO();
+                    newMembershipTO.setGroupKey(membPatch.getGroup());
+
+                    if (memb == null) {
+                        for (AttrPatch attrPatch : membPatch.getPlainAttrs()) {
+                            newMembershipTO.getPlainAttrs().add(attrPatch.getAttrTO());
+                        }
+                    } else {
+                        newMembershipTO.getPlainAttrs().addAll(
+                                patch(memb.getPlainAttrMap(), membPatch.getPlainAttrs()));
+                    }
+
+                    // 3. virtual attributes
+                    newMembershipTO.getVirAttrs().addAll(membPatch.getVirAttrs());
+
+                    result.getMemberships().add(newMembershipTO);
                 }
             }
         }
@@ -485,7 +514,7 @@ public final class AnyOperations {
 
     public static UserTO patch(final UserTO userTO, final UserPatch userPatch) {
         UserTO result = SerializationUtils.clone(userTO);
-        AnyOperations.patch(userTO, userPatch, result);
+        patch(userTO, userPatch, result);
 
         // 1. password
         if (userPatch.getPassword() != null) {
@@ -498,7 +527,7 @@ public final class AnyOperations {
         }
 
         // 3. relationships
-        for (final RelationshipPatch relPatch : userPatch.getRelationships()) {
+        for (RelationshipPatch relPatch : userPatch.getRelationships()) {
             if (relPatch.getRelationshipTO() == null) {
                 LOG.warn("Invalid {} specified: {}", RelationshipPatch.class.getName(), relPatch);
             } else {
@@ -511,12 +540,37 @@ public final class AnyOperations {
 
         // 4. memberships
         for (final MembershipPatch membPatch : userPatch.getMemberships()) {
-            if (membPatch.getMembershipTO() == null) {
+            if (membPatch.getGroup() == null) {
                 LOG.warn("Invalid {} specified: {}", MembershipPatch.class.getName(), membPatch);
             } else {
-                result.getMemberships().remove(membPatch.getMembershipTO());
+                MembershipTO memb = IterableUtils.find(result.getMemberships(), new Predicate<MembershipTO>() {
+
+                    @Override
+                    public boolean evaluate(final MembershipTO object) {
+                        return membPatch.getGroup().equals(object.getGroupKey());
+                    }
+                });
+                if (memb != null) {
+                    result.getMemberships().remove(memb);
+                }
+
                 if (membPatch.getOperation() == PatchOperation.ADD_REPLACE) {
-                    result.getMemberships().add(membPatch.getMembershipTO());
+                    MembershipTO newMembershipTO = new MembershipTO();
+                    newMembershipTO.setGroupKey(membPatch.getGroup());
+
+                    if (memb == null) {
+                        for (AttrPatch attrPatch : membPatch.getPlainAttrs()) {
+                            newMembershipTO.getPlainAttrs().add(attrPatch.getAttrTO());
+                        }
+                    } else {
+                        newMembershipTO.getPlainAttrs().addAll(
+                                patch(memb.getPlainAttrMap(), membPatch.getPlainAttrs()));
+                    }
+
+                    // 3. virtual attributes
+                    newMembershipTO.getVirAttrs().addAll(membPatch.getVirAttrs());
+
+                    result.getMemberships().add(newMembershipTO);
                 }
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
index e473e06..ddb4ac3 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyObjectPatch.java
@@ -32,10 +32,20 @@ public class AnyObjectPatch extends AnyPatch {
 
     private static final long serialVersionUID = -1644118942622556097L;
 
+    private StringReplacePatchItem name;
+
     private final Set<RelationshipPatch> relationships = new HashSet<>();
 
     private final Set<MembershipPatch> memberships = new HashSet<>();
 
+    public StringReplacePatchItem getName() {
+        return name;
+    }
+
+    public void setName(final StringReplacePatchItem name) {
+        this.name = name;
+    }
+
     @XmlElementWrapper(name = "relationships")
     @XmlElement(name = "relationship")
     @JsonProperty("relationships")

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
index 3ec141d..78e61dd 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AnyPatch.java
@@ -30,7 +30,7 @@ import org.apache.syncope.common.lib.AbstractBaseBean;
 import org.apache.syncope.common.lib.to.AttrTO;
 
 @XmlType
-public abstract class AnyPatch extends AbstractBaseBean {
+public abstract class AnyPatch extends AbstractBaseBean implements AttributablePatch {
 
     private static final long serialVersionUID = -7445489774552440544L;
 
@@ -70,16 +70,12 @@ public abstract class AnyPatch extends AbstractBaseBean {
         return auxClasses;
     }
 
-    @XmlElementWrapper(name = "plainAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("plainAttrs")
+    @Override
     public Set<AttrPatch> getPlainAttrs() {
         return plainAttrs;
     }
 
-    @XmlElementWrapper(name = "virAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("virAttrs")
+    @Override
     public Set<AttrTO> getVirAttrs() {
         return virAttrs;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.java
new file mode 100644
index 0000000..fa9d189
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/AttributablePatch.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.patch;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import org.apache.syncope.common.lib.to.AttrTO;
+
+public interface AttributablePatch {
+
+    @XmlElementWrapper(name = "plainAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("plainAttrs")
+    Set<AttrPatch> getPlainAttrs();
+
+    @XmlElementWrapper(name = "virAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("virAttrs")
+    Set<AttrTO> getVirAttrs();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
index b29a6de..0ed42c1 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/patch/MembershipPatch.java
@@ -18,13 +18,15 @@
  */
 package org.apache.syncope.common.lib.patch;
 
+import java.util.HashSet;
+import java.util.Set;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
-import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.AttrTO;
 
 @XmlRootElement(name = "membershipPatch")
 @XmlType
-public class MembershipPatch extends AbstractPatch {
+public class MembershipPatch extends AbstractPatch implements AttributablePatch {
 
     private static final long serialVersionUID = -6783121761221554433L;
 
@@ -35,20 +37,33 @@ public class MembershipPatch extends AbstractPatch {
             return new MembershipPatch();
         }
 
-        public Builder membershipTO(final MembershipTO membershipTO) {
-            getInstance().setMembershipTO(membershipTO);
+        public Builder group(final String group) {
+            getInstance().setGroup(group);
             return this;
         }
     }
 
-    private MembershipTO membershipTO;
+    private String group;
 
-    public MembershipTO getMembershipTO() {
-        return membershipTO;
+    private final Set<AttrPatch> plainAttrs = new HashSet<>();
+
+    private final Set<AttrTO> virAttrs = new HashSet<>();
+
+    public String getGroup() {
+        return group;
     }
 
-    public void setMembershipTO(final MembershipTO membershipTO) {
-        this.membershipTO = membershipTO;
+    public void setGroup(final String group) {
+        this.group = group;
     }
 
+    @Override
+    public Set<AttrPatch> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public Set<AttrTO> getVirAttrs() {
+        return virAttrs;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
index f652d76..d0bf7d4 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyObjectTO.java
@@ -37,12 +37,22 @@ public class AnyObjectTO extends AnyTO implements RelatableTO, GroupableTO {
 
     private static final long serialVersionUID = 8841697496476959639L;
 
+    private String name;
+
     private final List<RelationshipTO> relationships = new ArrayList<>();
 
     private final List<MembershipTO> memberships = new ArrayList<>();
 
     private final List<String> dynGroups = new ArrayList<>();
 
+    public String getName() {
+        return name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
     @XmlElementWrapper(name = "relationships")
     @XmlElement(name = "relationship")
     @JsonProperty("relationships")

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
index 4651835..7732bcc 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AnyTO.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.common.lib.to;
 
-import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import java.util.ArrayList;
@@ -30,15 +29,13 @@ 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.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlType;
 
-@XmlRootElement(name = "any")
 @XmlType
 @XmlSeeAlso({ UserTO.class, GroupTO.class, AnyObjectTO.class })
 @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
-public abstract class AnyTO extends ConnObjectTO implements EntityTO {
+public abstract class AnyTO extends AbstractAnnotatedBean implements EntityTO, AttributableTO {
 
     private static final long serialVersionUID = -754311920679872084L;
 
@@ -52,6 +49,8 @@ public abstract class AnyTO extends ConnObjectTO implements EntityTO {
 
     private final List<String> auxClasses = new ArrayList<>();
 
+    private final Set<AttrTO> plainAttrs = new HashSet<>();
+
     private final Set<AttrTO> derAttrs = new HashSet<>();
 
     private final Set<AttrTO> virAttrs = new HashSet<>();
@@ -99,14 +98,27 @@ public abstract class AnyTO extends ConnObjectTO implements EntityTO {
         return auxClasses;
     }
 
-    @XmlElementWrapper(name = "derAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("derAttrs")
+    @Override
+    public Set<AttrTO> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getPlainAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(plainAttrs.size());
+        for (AttrTO attributeTO : plainAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
     public Set<AttrTO> getDerAttrs() {
         return derAttrs;
     }
 
-    @JsonIgnore
+    @Override
     public Map<String, AttrTO> getDerAttrMap() {
         Map<String, AttrTO> result = new HashMap<>(derAttrs.size());
         for (AttrTO attributeTO : derAttrs) {
@@ -116,14 +128,12 @@ public abstract class AnyTO extends ConnObjectTO implements EntityTO {
         return Collections.unmodifiableMap(result);
     }
 
-    @XmlElementWrapper(name = "virAttrs")
-    @XmlElement(name = "attribute")
-    @JsonProperty("virAttrs")
+    @Override
     public Set<AttrTO> getVirAttrs() {
         return virAttrs;
     }
 
-    @JsonIgnore
+    @Override
     public Map<String, AttrTO> getVirAttrMap() {
         Map<String, AttrTO> result = new HashMap<>(virAttrs.size());
         for (AttrTO attributeTO : virAttrs) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.java
new file mode 100644
index 0000000..51ee0fc
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/AttributableTO.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.to;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+
+public interface AttributableTO {
+
+    @XmlElementWrapper(name = "plainAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("plainAttrs")
+    Set<AttrTO> getPlainAttrs();
+
+    @JsonIgnore
+    Map<String, AttrTO> getPlainAttrMap();
+
+    @XmlElementWrapper(name = "derAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("derAttrs")
+    Set<AttrTO> getDerAttrs();
+
+    @JsonIgnore
+    Map<String, AttrTO> getDerAttrMap();
+
+    @XmlElementWrapper(name = "virAttrs")
+    @XmlElement(name = "attribute")
+    @JsonProperty("virAttrs")
+    Set<AttrTO> getVirAttrs();
+
+    @JsonIgnore
+    Map<String, AttrTO> getVirAttrMap();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
index 82878f8..8f65b70 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/ConnObjectTO.java
@@ -29,19 +29,20 @@ 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 = "connObject")
 @XmlType
-public class ConnObjectTO extends AbstractAnnotatedBean {
+public class ConnObjectTO extends AbstractBaseBean {
 
     private static final long serialVersionUID = 5139554911265442497L;
 
     private final Set<AttrTO> attrs = new LinkedHashSet<>();
 
-    @XmlElementWrapper(name = "plainAttrs")
+    @XmlElementWrapper(name = "attrs")
     @XmlElement(name = "attribute")
-    @JsonProperty("plainAttrs")
-    public Set<AttrTO> getPlainAttrs() {
+    @JsonProperty("attrs")
+    public Set<AttrTO> getAttrs() {
         return attrs;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
index 6ded46b..58f3d9d 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/MembershipTO.java
@@ -18,13 +18,19 @@
  */
 package org.apache.syncope.common.lib.to;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 
 @XmlRootElement(name = "membership")
 @XmlType
-public class MembershipTO extends RelationshipTO {
+public class MembershipTO extends RelationshipTO implements AttributableTO {
 
     private static final long serialVersionUID = 5992828670273935861L;
 
@@ -32,12 +38,6 @@ public class MembershipTO extends RelationshipTO {
 
         private final MembershipTO instance = new MembershipTO();
 
-        public Builder left(final String leftType, final String leftKey) {
-            instance.setLeftType(leftType);
-            instance.setLeftKey(leftKey);
-            return this;
-        }
-
         public Builder group(final String groupKey) {
             instance.setRightKey(groupKey);
             return this;
@@ -56,6 +56,12 @@ public class MembershipTO extends RelationshipTO {
 
     private String groupName;
 
+    private final Set<AttrTO> plainAttrs = new HashSet<>();
+
+    private final Set<AttrTO> derAttrs = new HashSet<>();
+
+    private final Set<AttrTO> virAttrs = new HashSet<>();
+
     @Override
     public String getType() {
         return "Membership";
@@ -76,6 +82,15 @@ public class MembershipTO extends RelationshipTO {
         // ignore
     }
 
+    @JsonIgnore
+    public String getGroupKey() {
+        return getRightKey();
+    }
+
+    public void setGroupKey(final String groupKey) {
+        setRightKey(groupKey);
+    }
+
     public String getGroupName() {
         return groupName;
     }
@@ -83,4 +98,50 @@ public class MembershipTO extends RelationshipTO {
     public void setGroupName(final String groupName) {
         this.groupName = groupName;
     }
+
+    @Override
+    public Set<AttrTO> getPlainAttrs() {
+        return plainAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getPlainAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(plainAttrs.size());
+        for (AttrTO attributeTO : plainAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Set<AttrTO> getDerAttrs() {
+        return derAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getDerAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(derAttrs.size());
+        for (AttrTO attributeTO : derAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
+    @Override
+    public Set<AttrTO> getVirAttrs() {
+        return virAttrs;
+    }
+
+    @Override
+    public Map<String, AttrTO> getVirAttrMap() {
+        Map<String, AttrTO> result = new HashMap<>(virAttrs.size());
+        for (AttrTO attributeTO : virAttrs) {
+            result.put(attributeTO.getSchema(), attributeTO);
+        }
+
+        return Collections.unmodifiableMap(result);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
index 29326c2..fc5de4f 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/RelationshipTO.java
@@ -37,12 +37,6 @@ public class RelationshipTO extends AbstractBaseBean {
             return this;
         }
 
-        public Builder left(final String leftType, final String leftKey) {
-            instance.setLeftType(leftType);
-            instance.setLeftKey(leftKey);
-            return this;
-        }
-
         public Builder right(final String rightType, final String rightKey) {
             instance.setRightType(rightType);
             instance.setRightKey(rightKey);
@@ -56,10 +50,6 @@ public class RelationshipTO extends AbstractBaseBean {
 
     private String type;
 
-    private String leftType;
-
-    private String leftKey;
-
     private String rightType;
 
     private String rightKey;
@@ -72,22 +62,6 @@ public class RelationshipTO extends AbstractBaseBean {
         this.type = type;
     }
 
-    public String getLeftType() {
-        return leftType;
-    }
-
-    public void setLeftType(final String leftType) {
-        this.leftType = leftType;
-    }
-
-    public String getLeftKey() {
-        return leftKey;
-    }
-
-    public void setLeftKey(final String leftKey) {
-        this.leftKey = leftKey;
-    }
-
     public String getRightType() {
         return rightType;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
index 7532730..db3e329 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/EntityViolationType.java
@@ -43,9 +43,7 @@ public enum EntityViolationType {
     InvalidSchemaMultivalueUnique("org.apache.syncope.core.persistence.validation.schema.multivalueUnique"),
     InvalidSchedTask("org.apache.syncope.core.persistence.validation.schedtask"),
     InvalidProvisioningTask("org.apache.syncope.core.persistence.validation.provisioningtask"),
-    InvalidPlainSchema("org.apache.syncope.core.persistence.validation.attrvalue.plainSchema"),
-    InvalidDerSchema("org.apache.syncope.core.persistence.validation.attrvalue.derSchema"),
-    InvalidVirSchema("org.apache.syncope.core.persistence.validation.attrvalue.virSchema"),
+    InvalidPlainAttr("org.apache.syncope.core.persistence.validation.plainattr"),
     InvalidUsername("org.apache.syncope.core.persistence.validation.user.username"),
     InvalidValueList("org.apache.syncope.core.persistence.validation.attr.valueList"),
     MoreThanOneNonNull("org.apache.syncope.core.persistence.validation.attrvalue.moreThanOneNonNull");

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java b/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
index eccb89d..8553348 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/types/IntMappingType.java
@@ -56,7 +56,8 @@ public enum IntMappingType {
     AnyObjectPlainSchema(AnyTypeKind.ANY_OBJECT),
     AnyObjectDerivedSchema(AnyTypeKind.ANY_OBJECT),
     AnyObjectVirtualSchema(AnyTypeKind.ANY_OBJECT),
-    AnyObjectKey(AnyTypeKind.ANY_OBJECT);
+    AnyObjectKey(AnyTypeKind.ANY_OBJECT),
+    AnyObjectName(AnyTypeKind.ANY_OBJECT);
 
     private final AnyTypeKind anyTypeKind;
 
@@ -119,7 +120,7 @@ public enum IntMappingType {
     public static Set<IntMappingType> getEmbedded() {
         return EnumSet.of(IntMappingType.UserKey, IntMappingType.Username, IntMappingType.Password,
                 IntMappingType.GroupKey, IntMappingType.GroupName, IntMappingType.GroupOwnerSchema,
-                IntMappingType.AnyObjectKey);
+                IntMappingType.AnyObjectKey, IntMappingType.AnyObjectName);
     }
 
     /**
@@ -195,7 +196,8 @@ public enum IntMappingType {
         AnyObjectPlainSchema,
         AnyObjectDerivedSchema,
         AnyObjectVirtualSchema,
-        AnyObjectKey;
+        AnyObjectKey,
+        AnyObjectName;
 
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
new file mode 100644
index 0000000..6c04ac4
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AllowedSchemas.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.dao;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
+import org.apache.commons.collections4.PredicateUtils;
+import org.apache.commons.collections4.SetUtils;
+import org.apache.syncope.core.persistence.api.entity.Schema;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
+
+public class AllowedSchemas<S extends Schema> {
+
+    private final Set<S> forSelf = new HashSet<>();
+
+    private final Map<Group, Set<S>> forMemberships = new HashMap<>();
+
+    public Set<S> getForSelf() {
+        return forSelf;
+    }
+
+    public Set<S> getForMembership(final Group group) {
+        return SetUtils.emptyIfNull(forMemberships.get(group));
+    }
+
+    public Map<Group, Set<S>> getForMemberships() {
+        return forMemberships;
+    }
+
+    public boolean forSelfContains(final S schema) {
+        return forSelf.contains(schema);
+    }
+
+    public boolean forSelfContains(final String schema) {
+        return IterableUtils.matchesAny(forSelf, new KeyMatches(schema));
+    }
+
+    public boolean forMembershipsContains(final Group group, final S schema) {
+        return IterableUtils.matchesAny(forMemberships.get(group), PredicateUtils.equalPredicate(schema));
+    }
+
+    public boolean forMembershipsContains(final S schema) {
+        for (Map.Entry<Group, Set<S>> entry : forMemberships.entrySet()) {
+            if (entry.getValue().contains(schema)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean forMembershipsContains(final Group group, final String schema) {
+        return IterableUtils.matchesAny(forMemberships.get(group), new KeyMatches(schema));
+    }
+
+    public boolean forMembershipsContains(final String schema) {
+        KeyMatches keyMatches = new KeyMatches(schema);
+
+        for (Map.Entry<Group, Set<S>> entry : forMemberships.entrySet()) {
+            if (IterableUtils.matchesAny(entry.getValue(), keyMatches)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean contains(final S schema) {
+        if (forSelfContains(schema)) {
+            return true;
+        }
+        return forMembershipsContains(schema);
+    }
+
+    public boolean contains(final String schema) {
+        if (forSelfContains(schema)) {
+            return true;
+        }
+        return forMembershipsContains(schema);
+    }
+
+    private class KeyMatches implements Predicate<S> {
+
+        private final String schema;
+
+        KeyMatches(final String schema) {
+            this.schema = schema;
+        }
+
+        @Override
+        public boolean evaluate(final S object) {
+            return object.getKey().equals(schema);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
index b6d78fd..6b2fd4e 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyDAO.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.core.persistence.api.dao;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
@@ -72,7 +71,7 @@ public interface AnyDAO<A extends Any<?>> extends DAO<A> {
      */
     List<A> findAll(Set<String> adminRealms, int page, int itemsPerPage, List<OrderByClause> orderBy);
 
-    <S extends Schema> Collection<S> findAllowedSchemas(A any, Class<S> reference);
+    <S extends Schema> AllowedSchemas<S> findAllowedSchemas(A any, Class<S> reference);
 
     int count(Set<String> adminRealms);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
index bdf9642..c24b37d 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AnyObjectDAO.java
@@ -40,6 +40,10 @@ public interface AnyObjectDAO extends AnyDAO<AnyObject> {
 
     Map<String, Integer> countByRealm(AnyType anyType);
 
+    AnyObject findByName(String name);
+
+    AnyObject authFindByName(String name);
+
     List<Group> findDynGroupMemberships(AnyObject anyObject);
 
     List<ARelationship> findARelationships(AnyObject anyObject);

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
index b1580e3..82359e9 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Any.java
@@ -41,6 +41,8 @@ public interface Any<P extends PlainAttr<?>> extends AnnotatedEntity {
 
     boolean add(P attr);
 
+    boolean remove(P attr);
+
     P getPlainAttr(String plainSchemaName);
 
     List<? extends P> getPlainAttrs();

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
index 377f7fe..0e0c8cc 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/AnyUtils.java
@@ -22,6 +22,7 @@ import java.util.Set;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.IntMappingType;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 
 public interface AnyUtils {
@@ -52,5 +53,5 @@ public interface AnyUtils {
 
     Set<ExternalResource> getAllResources(Any<?> any);
 
-    <S extends Schema> Set<S> getAllowedSchemas(Any<?> any, Class<S> reference);
+    <S extends Schema> AllowedSchemas<S> getAllowedSchemas(Any<?> any, Class<S> reference);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java
new file mode 100644
index 0000000..7e345a5
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupablePlainAttr.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.entity;
+
+public interface GroupablePlainAttr<A extends Any<?>, M extends Membership<A>> extends PlainAttr<A> {
+
+    M getMembership();
+
+    void setMembership(M membership);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
new file mode 100644
index 0000000..147f469
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GroupableRelatable.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.persistence.api.entity;
+
+import java.util.Collection;
+import java.util.List;
+
+public interface GroupableRelatable<
+        L extends Any<P>, 
+        M extends Membership<L>, 
+        P extends GroupablePlainAttr<L, M>,
+        R extends Any<?>,
+        REL extends Relationship<L, R>> extends Any<P> {
+
+    @Override
+    boolean add(final P attr);
+
+    @Override
+    boolean remove(final P attr);
+
+    /**
+     * Returns the plain attribute for this instance and the given schema name - if found, {@code NULL} otherwise.
+     * <b>IMPORTANT:</b> This method won't return any attribute related to memberships.
+     *
+     * @param plainSchemaName plain schema name
+     * @return plain attribute for this instance and the given schema name - if found, {@code NULL} otherwise
+     */
+    @Override
+    P getPlainAttr(String plainSchemaName);
+
+    /**
+     * Returns the plain attribute for this instance, the given schema name and the given membership -
+     * if found, {@code NULL} otherwise.
+     *
+     * @param plainSchemaName plain schema name
+     * @param membership membership
+     * @return plain attribute for this instance, the given schema name and the given membership -
+     * if found, {@code NULL} otherwise
+     */
+    P getPlainAttr(String plainSchemaName, Membership<?> membership);
+
+    /**
+     * Returns the plain attributes for this instance.
+     * <b>IMPORTANT:</b> This method won't return any attribute related to memberships.
+     *
+     * @return plain attribute for this instance
+     */
+    @Override
+    List<? extends P> getPlainAttrs();
+
+    /**
+     * Returns the list of plain attributes for this instance and the given schema name (including membeship attributes,
+     * as opposite to {@link Any#getPlainAttr(java.lang.String)}).
+     *
+     * @param plainSchemaName plain schema name
+     * @return list of plain attributes for this instance and the given schema name (including membeship attributes)
+     */
+    Collection<? extends P> getPlainAttrs(String plainSchemaName);
+
+    /**
+     * Returns the list of plain attributes for this instance and the given membership.
+     *
+     * @param membership membership
+     * @return list of plain attributes for this instance and the given membership
+     */
+    Collection<? extends P> getPlainAttrs(Membership<?> membership);
+
+    boolean add(M membership);
+
+    M getMembership(String groupKey);
+
+    List<? extends M> getMemberships();
+
+    boolean add(REL relationship);
+
+    REL getRelationship(RelationshipType relationshipType, String otherEndKey);
+
+    Collection<? extends REL> getRelationships(String otherEndKey);
+
+    Collection<? extends REL> getRelationships(RelationshipType relationshipType);
+
+    List<? extends REL> getRelationships();
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
index 46d2297..64a58ce 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/APlainAttr.java
@@ -19,9 +19,9 @@
 package org.apache.syncope.core.persistence.api.entity.anyobject;
 
 import java.util.List;
-import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
 
-public interface APlainAttr extends PlainAttr<AnyObject> {
+public interface APlainAttr extends GroupablePlainAttr<AnyObject, AMembership> {
 
     @Override
     List<? extends APlainAttrValue> getValues();

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
index ac5fda0..7b0f434 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/anyobject/AnyObject.java
@@ -18,27 +18,13 @@
  */
 package org.apache.syncope.core.persistence.api.entity.anyobject;
 
-import java.util.Collection;
-import java.util.List;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.RelationshipType;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 
-public interface AnyObject extends Any<APlainAttr> {
+public interface AnyObject extends
+        GroupableRelatable<AnyObject, AMembership, APlainAttr, AnyObject, ARelationship> {
 
-    boolean add(ARelationship relationship);
+    String getName();
 
-    ARelationship getRelationship(RelationshipType relationshipType, String anyObjectKey);
-
-    Collection<? extends ARelationship> getRelationships(String anyObjectKey);
-
-    Collection<? extends ARelationship> getRelationships(RelationshipType relationshipType);
-
-    List<? extends ARelationship> getRelationships();
-
-    boolean add(AMembership membership);
-
-    AMembership getMembership(String membershipKey);
-
-    List<? extends AMembership> getMemberships();
+    void setName(String name);
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
index 5c91acf..503352f 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/UPlainAttr.java
@@ -19,9 +19,9 @@
 package org.apache.syncope.core.persistence.api.entity.user;
 
 import java.util.List;
-import org.apache.syncope.core.persistence.api.entity.PlainAttr;
+import org.apache.syncope.core.persistence.api.entity.GroupablePlainAttr;
 
-public interface UPlainAttr extends PlainAttr<User> {
+public interface UPlainAttr extends GroupablePlainAttr<User, UMembership> {
 
     @Override
     List<? extends UPlainAttrValue> getValues();

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
index b7e14bf..fa81fd1 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/user/User.java
@@ -18,15 +18,15 @@
  */
 package org.apache.syncope.core.persistence.api.entity.user;
 
-import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import org.apache.syncope.common.lib.types.CipherAlgorithm;
-import org.apache.syncope.core.persistence.api.entity.Any;
-import org.apache.syncope.core.persistence.api.entity.RelationshipType;
 import org.apache.syncope.core.persistence.api.entity.Role;
+import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.GroupableRelatable;
 
-public interface User extends Any<UPlainAttr> {
+public interface User extends
+        GroupableRelatable<User, UMembership, UPlainAttr, AnyObject, URelationship> {
 
     String getUsername();
 
@@ -92,32 +92,8 @@ public interface User extends Any<UPlainAttr> {
 
     void setMustChangePassword(boolean mustChangePassword);
 
-    @Override
-    boolean add(UPlainAttr attr);
-
-    @Override
-    UPlainAttr getPlainAttr(String plainSchemaName);
-
-    @Override
-    List<? extends UPlainAttr> getPlainAttrs();
-
     boolean add(Role role);
 
     List<? extends Role> getRoles();
 
-    boolean add(URelationship relationship);
-
-    URelationship getRelationship(RelationshipType relationshipType, String anyObjectKey);
-
-    Collection<? extends URelationship> getRelationships(String anyObjectKey);
-
-    Collection<? extends URelationship> getRelationships(RelationshipType relationshipType);
-
-    List<? extends URelationship> getRelationships();
-
-    boolean add(UMembership membership);
-
-    UMembership getMembership(String groupKey);
-
-    List<? extends UMembership> getMemberships();
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
index 379d386..0eb38ac 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/AbstractAnyDAO.java
@@ -23,8 +23,10 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
 import javax.persistence.NoResultException;
@@ -35,6 +37,7 @@ import org.apache.commons.jexl3.parser.ParserConstants;
 import org.apache.commons.jexl3.parser.Token;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.core.persistence.api.dao.AllowedSchemas;
 import org.apache.syncope.core.persistence.api.dao.AnyDAO;
 import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
 import org.apache.syncope.core.persistence.api.dao.DerSchemaDAO;
@@ -54,6 +57,7 @@ import org.apache.syncope.core.persistence.api.entity.Schema;
 import org.apache.syncope.core.persistence.api.entity.VirSchema;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
+import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.persistence.api.entity.group.TypeExtension;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.user.UMembership;
@@ -420,33 +424,55 @@ public abstract class AbstractAnyDAO<A extends Any<?>> extends AbstractDAO<A> im
     @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)
     @Override
     @SuppressWarnings("unchecked")
-    public <S extends Schema> Collection<S> findAllowedSchemas(final A any, final Class<S> reference) {
-        Set<AnyTypeClass> classes = new HashSet<>();
-        classes.addAll(any.getType().getClasses());
-        classes.addAll(any.getAuxClasses());
+    public <S extends Schema> AllowedSchemas<S> findAllowedSchemas(final A any, final Class<S> reference) {
+        AllowedSchemas<S> result = new AllowedSchemas<>();
+
+        // schemas given by type and aux classes
+        Set<AnyTypeClass> typeOwnClasses = new HashSet<>();
+        typeOwnClasses.addAll(any.getType().getClasses());
+        typeOwnClasses.addAll(any.getAuxClasses());
+
+        for (AnyTypeClass typeClass : typeOwnClasses) {
+            if (reference.equals(PlainSchema.class)) {
+                result.getForSelf().addAll((Collection<? extends S>) typeClass.getPlainSchemas());
+            } else if (reference.equals(DerSchema.class)) {
+                result.getForSelf().addAll((Collection<? extends S>) typeClass.getDerSchemas());
+            } else if (reference.equals(VirSchema.class)) {
+                result.getForSelf().addAll((Collection<? extends S>) typeClass.getVirSchemas());
+            }
+        }
+
+        // schemas given by type extensions
+        Map<Group, List<? extends AnyTypeClass>> typeExtensionClasses = new HashMap<>();
         if (any instanceof User) {
             for (UMembership memb : ((User) any).getMemberships()) {
                 for (TypeExtension typeExtension : memb.getRightEnd().getTypeExtensions()) {
-                    classes.addAll(typeExtension.getAuxClasses());
+                    typeExtensionClasses.put(memb.getRightEnd(), typeExtension.getAuxClasses());
                 }
             }
         } else if (any instanceof AnyObject) {
             for (AMembership memb : ((AnyObject) any).getMemberships()) {
                 for (TypeExtension typeExtension : memb.getRightEnd().getTypeExtensions()) {
-                    classes.addAll(typeExtension.getAuxClasses());
+                    if (any.getType().equals(typeExtension.getAnyType())) {
+                        typeExtensionClasses.put(memb.getRightEnd(), typeExtension.getAuxClasses());
+                    }
                 }
             }
         }
 
-        Set<S> result = new HashSet<>();
-
-        for (AnyTypeClass typeClass : classes) {
-            if (reference.equals(PlainSchema.class)) {
-                result.addAll((Collection<? extends S>) typeClass.getPlainSchemas());
-            } else if (reference.equals(DerSchema.class)) {
-                result.addAll((Collection<? extends S>) typeClass.getDerSchemas());
-            } else if (reference.equals(VirSchema.class)) {
-                result.addAll((Collection<? extends S>) typeClass.getVirSchemas());
+        for (Map.Entry<Group, List<? extends AnyTypeClass>> entry : typeExtensionClasses.entrySet()) {
+            result.getForMemberships().put(entry.getKey(), new HashSet<S>());
+            for (AnyTypeClass typeClass : entry.getValue()) {
+                if (reference.equals(PlainSchema.class)) {
+                    result.getForMemberships().get(entry.getKey()).
+                            addAll((Collection<? extends S>) typeClass.getPlainSchemas());
+                } else if (reference.equals(DerSchema.class)) {
+                    result.getForMemberships().get(entry.getKey()).
+                            addAll((Collection<? extends S>) typeClass.getDerSchemas());
+                } else if (reference.equals(VirSchema.class)) {
+                    result.getForMemberships().get(entry.getKey()).
+                            addAll((Collection<? extends S>) typeClass.getVirSchemas());
+                }
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
index 60be1fe..5280c3c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAAnyObjectDAO.java
@@ -27,6 +27,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.persistence.NoResultException;
 import javax.persistence.Query;
 import javax.persistence.TypedQuery;
 import org.apache.commons.collections4.CollectionUtils;
@@ -40,6 +41,7 @@ import org.apache.syncope.core.spring.security.DelegatedAdministrationException;
 import org.apache.syncope.core.provisioning.api.utils.EntityUtils;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.GroupDAO;
+import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
 import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
@@ -124,6 +126,38 @@ public class JPAAnyObjectDAO extends AbstractAnyDAO<AnyObject> implements AnyObj
     }
 
     @Override
+    public AnyObject findByName(final String name) {
+        TypedQuery<AnyObject> query = entityManager().createQuery(
+                "SELECT e FROM " + JPAAnyObject.class.getSimpleName() + " e WHERE e.name = :name", AnyObject.class);
+        query.setParameter("name", name);
+
+        AnyObject result = null;
+        try {
+            result = query.getSingleResult();
+        } catch (NoResultException e) {
+            LOG.debug("No any object found with name {}", name, e);
+        }
+
+        return result;
+    }
+
+    @Override
+    public AnyObject authFindByName(final String name) {
+        if (name == null) {
+            throw new NotFoundException("Null name");
+        }
+
+        AnyObject anyObject = findByName(name);
+        if (anyObject == null) {
+            throw new NotFoundException("Any Object " + name);
+        }
+
+        securityChecks(anyObject);
+
+        return anyObject;
+    }
+
+    @Override
     public List<ARelationship> findARelationships(final AnyObject anyObject) {
         TypedQuery<ARelationship> query = entityManager().createQuery(
                 "SELECT e FROM " + JPAARelationship.class.getSimpleName()

http://git-wip-us.apache.org/repos/asf/syncope/blob/f0ef4df2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
index 07e18e2..d1df518 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAConfDAO.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.core.persistence.jpa.dao;
 
 import org.apache.syncope.core.persistence.api.dao.ConfDAO;
-import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
 import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
 import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue;
 import org.apache.syncope.core.persistence.api.entity.PlainSchema;
@@ -40,9 +39,6 @@ public class JPAConfDAO extends AbstractDAO<Conf> implements ConfDAO {
     @Autowired
     private PlainSchemaDAO schemaDAO;
 
-    @Autowired
-    private PlainAttrDAO attrDAO;
-
     @Override
     public Conf get() {
         Conf instance = entityManager().find(JPAConf.class, KEY);
@@ -96,8 +92,8 @@ public class JPAConfDAO extends AbstractDAO<Conf> implements ConfDAO {
         if (old != null && (!attr.getSchema().isUniqueConstraint()
                 || (!attr.getUniqueValue().getStringValue().equals(old.getUniqueValue().getStringValue())))) {
 
-            instance.getPlainAttrs().remove(old);
-            attrDAO.delete(old.getKey(), CPlainAttr.class);
+            old.setOwner(null);
+            instance.remove(old);
         }
 
         instance.add(attr);
@@ -111,8 +107,8 @@ public class JPAConfDAO extends AbstractDAO<Conf> implements ConfDAO {
         Conf instance = get();
         CPlainAttr attr = instance.getPlainAttr(key);
         if (attr != null) {
-            instance.getPlainAttrs().remove(attr);
-            attrDAO.delete(attr.getKey(), CPlainAttr.class);
+            attr.setOwner(null);
+            instance.remove(attr);
 
             instance = entityManager().merge(instance);
         }