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/04/26 17:46:31 UTC

[1/4] syncope git commit: [SYNCOPE-790] Now binding JSON configuration to role which allows to selectively enable user / group / anyObject wizard steps, customize plain / derived / virtual attributes appearance order and even providing custom class

Repository: syncope
Updated Branches:
  refs/heads/master 22b893d24 -> 5b47ab235


http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
index 1b74b98..919c3cb 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPARole.java
@@ -31,6 +31,7 @@ import javax.persistence.Entity;
 import javax.persistence.FetchType;
 import javax.persistence.JoinColumn;
 import javax.persistence.JoinTable;
+import javax.persistence.Lob;
 import javax.persistence.ManyToMany;
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
@@ -70,6 +71,9 @@ public class JPARole extends AbstractProvidedKeyEntity implements Role {
     @Valid
     private JPADynRoleMembership dynMembership;
 
+    @Lob
+    private String consoleLayoutInfo;
+
     @Override
     public Set<String> getEntitlements() {
         return entitlements;
@@ -96,4 +100,15 @@ public class JPARole extends AbstractProvidedKeyEntity implements Role {
         checkType(dynMembership, JPADynRoleMembership.class);
         this.dynMembership = (JPADynRoleMembership) dynMembership;
     }
+
+    @Override
+    public String getConsoleLayoutInfo() {
+        return consoleLayoutInfo;
+    }
+
+    @Override
+    public void setConsoleLayoutInfo(final String consoleLayoutInfo) {
+        this.consoleLayoutInfo = consoleLayoutInfo;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/resources/domains/MasterContent.xml b/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
index a497a36..b5b4c9a 100644
--- a/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/main/resources/domains/MasterContent.xml
@@ -112,20 +112,6 @@ under the License.
               owner_id="cd64d66f-6fff-4008-b966-a06b1cc1436d" schema_id="return.password.value"/>
   <CPlainAttrValue id="e5fa94db-b524-4309-908d-8198d0b3f779"
                    attribute_id="bcfd7efc-0605-4b5e-b4bb-85c1d5f6493a" booleanValue="0"/>
-  
-  <!-- For usage with admin console -->
-  <PlainSchema id="admin.user.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="self.user.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="admin.group.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="self.group.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="admin.membership.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="self.membership.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
 
   <AnyType id="USER" kind="USER"/>
   <AnyTypeClass id="BaseUser"/>

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
index 4b402bd..e82efa6 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/MultitenancyTest.java
@@ -83,7 +83,7 @@ public class MultitenancyTest extends AbstractTest {
 
     @Test
     public void readPlainSchemas() {
-        assertEquals(17, plainSchemaDAO.findAll().size());
+        assertEquals(11, plainSchemaDAO.findAll().size());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
index 21636b7..8ded618 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/PlainSchemaTest.java
@@ -47,7 +47,7 @@ public class PlainSchemaTest extends AbstractTest {
     @Test
     public void findAll() {
         List<PlainSchema> schemas = plainSchemaDAO.findAll();
-        assertEquals(44, schemas.size());
+        assertEquals(38, schemas.size());
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/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 ca006ef..f1a88a0 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -113,20 +113,6 @@ under the License.
   <CPlainAttrValue id="e5fa94db-b524-4309-908d-8198d0b3f779"
                    attribute_id="bcfd7efc-0605-4b5e-b4bb-85c1d5f6493a" booleanValue="0"/>
   
-  <!-- For usage with admin console -->
-  <PlainSchema id="admin.user.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="self.user.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="admin.group.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="self.group.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="admin.membership.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="self.membership.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  
   <!-- sample policies -->
   <PullPolicy id="66691e96-285f-4464-bc19-e68384ea4c85" description="a pull policy"
               specification='{"conflictResolutionAction":"IGNORE"}'/>
@@ -1139,7 +1125,7 @@ we are happy to inform you that the password request was execute successfully fo
 Best regards."
                 htmlTemplate="&lt;html&gt;
 &lt;body&gt;
-&lt;p&gt;Hi,&lt;/br&gt;
+&lt;p&gt;Hi,&lt;br/&gt;
 we are happy to inform you that the password request was execute successfully for your account.&lt;/p&gt;
 
 &lt;p&gt;Best regards.&lt;/p&gt;

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/resources/domains/TwoContent.xml b/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
index cd88c6e..a24431e 100644
--- a/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/TwoContent.xml
@@ -100,20 +100,6 @@ under the License.
   <AnyType_AnyTypeClass anyType_id="USER" anyTypeClass_id="BaseUser"/>
 
   <AnyType id="GROUP" kind="GROUP"/>
-  
-  <!-- For usage with admin console -->
-  <PlainSchema id="admin.user.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="self.user.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="admin.group.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="self.group.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="admin.membership.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
-  <PlainSchema id="self.membership.layout" type="String"
-               mandatoryCondition="false" multivalue="1" uniqueConstraint="0" readonly="0"/>
         
   <PlainSchema id="email" type="String" anyTypeClass_id="BaseUser"
                mandatoryCondition="false" multivalue="0" uniqueConstraint="0" readonly="0"

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/RoleServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/RoleServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/RoleServiceImpl.java
index 1eec4a3..5e47078 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/RoleServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/RoleServiceImpl.java
@@ -18,9 +18,17 @@
  */
 package org.apache.syncope.core.rest.cxf.service;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.URI;
 import java.util.List;
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import org.apache.commons.io.IOUtils;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.RoleTO;
 import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.common.rest.api.service.RoleService;
@@ -63,4 +71,34 @@ public class RoleServiceImpl extends AbstractServiceImpl implements RoleService
         logic.delete(key);
     }
 
+    @Override
+    public Response getConsoleLayoutInfo(final String key) {
+        final String template = logic.getConsoleLayoutInfo(key);
+        StreamingOutput sout = new StreamingOutput() {
+
+            @Override
+            public void write(final OutputStream os) throws IOException {
+                os.write(template.getBytes());
+            }
+        };
+        return Response.ok(sout).
+                type(MediaType.APPLICATION_JSON_TYPE).
+                build();
+    }
+
+    @Override
+    public void setConsoleLayoutInfo(final String key, final InputStream consoleLayoutIn) {
+        try {
+            logic.setConsoleLayoutInfo(key, IOUtils.toString(consoleLayoutIn, SyncopeConstants.DEFAULT_CHARSET));
+        } catch (final IOException e) {
+            LOG.error("While setting console layout info for role {}", key, e);
+            throw new InternalServerErrorException("Could not read entity", e);
+        }
+    }
+
+    @Override
+    public void removeConsoleLayoutInfo(final String key) {
+        logic.setConsoleLayoutInfo(key, null);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/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 4eaa5e6..bbfa9ad 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
@@ -616,7 +616,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         if (user == null) {
             throw new NotFoundException("User with workflow id " + processInstanceId);
         }
-        formTO.setUserKey(user.getKey());
+        formTO.setUsername(user.getUsername());
 
         formTO.setTaskId(taskId);
         formTO.setKey(formKey);
@@ -645,7 +645,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
         if (user == null) {
             throw new NotFoundException("User with workflow id " + processInstanceId);
         }
-        formTO.setUserKey(user.getKey());
+        formTO.setUsername(user.getUsername());
 
         formTO.setTaskId(taskId);
         formTO.setKey(formKey);

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.java
----------------------------------------------------------------------
diff --git a/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.java b/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.java
index cc73d4d..a25d49d 100644
--- a/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.java
+++ b/ext/camel/client-console/src/main/java/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.java
@@ -48,6 +48,8 @@ public class CamelRoutesDetailsPanel extends Panel {
         response.render(OnLoadHeaderItem.forScript(
                 "CodeMirror.fromTextArea(document.getElementById('route'), {"
                 + "  lineNumbers: true, "
+                + "  autoCloseTags: true, "
+                + "  mode: 'text/html', "
                 + "  autoRefresh: true"
                 + "}).on('change', updateTextArea);"));
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.html
----------------------------------------------------------------------
diff --git a/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.html b/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.html
index 882ac6f..8edd764 100644
--- a/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.html
+++ b/ext/camel/client-console/src/main/resources/org/apache/syncope/client/console/panels/CamelRoutesDetailsPanel.html
@@ -25,6 +25,7 @@ under the License.
     <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/display/autorefresh.js"></script>
     <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/search/search.js"></script>
     <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/search/searchcursor.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/edit/closetag.js"></script>
     <script type="text/javascript">
       function updateTextArea(editor) {
         document.getElementById("routeDefForm").elements["route"].value = editor.getValue();

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BaseITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BaseITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BaseITCase.java
index 40ed0e5..20c7a3d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BaseITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/BaseITCase.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.fit.console;
 
 import org.apache.syncope.client.console.pages.Dashboard;
-import org.apache.syncope.client.console.pages.Layouts;
 import org.apache.syncope.client.console.pages.Login;
 import org.apache.syncope.client.console.pages.Logs;
 import org.apache.syncope.client.console.pages.Notifications;
@@ -88,9 +87,6 @@ public class BaseITCase extends AbstractConsoleITCase {
         wicketTester.clickLink("body:configurationLI:configurationUL:policiesLI:policies");
         wicketTester.assertRenderedPage(Policies.class);
 
-        wicketTester.clickLink("body:configurationLI:configurationUL:layoutsLI:layouts");
-        wicketTester.assertRenderedPage(Layouts.class);
-
         wicketTester.clickLink("body:configurationLI:configurationUL:notificationsLI:notifications");
         wicketTester.assertRenderedPage(Notifications.class);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
index 7d6e0c9..97745c3 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MultitenancyITCase.java
@@ -104,7 +104,7 @@ public class MultitenancyITCase extends AbstractITCase {
 
     @Test
     public void readPlainSchemas() {
-        assertEquals(17, adminClient.getService(SchemaService.class).
+        assertEquals(11, adminClient.getService(SchemaService.class).
                 list(new SchemaQuery.Builder().type(SchemaType.PLAIN).build()).size());
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
index 32c8269..3df0b3e 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
@@ -74,8 +74,8 @@ public class UserWorkflowITCase extends AbstractITCase {
         // 2. request if there is any pending task for user just created
         WorkflowFormTO form = userWorkflowService.getFormForUser(userTO.getKey());
         assertNotNull(form);
-        assertNotNull(form.getUserKey());
-        assertEquals(userTO.getKey(), form.getUserKey());
+        assertNotNull(form.getUsername());
+        assertEquals(userTO.getUsername(), form.getUsername());
         assertNotNull(form.getTaskId());
         assertNull(form.getOwner());
 


[4/4] syncope git commit: Preventing NPE for bad search queries

Posted by il...@apache.org.
Preventing NPE for bad search queries


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

Branch: refs/heads/master
Commit: 8dc9ec5f75af0bfbd67f7daf897ee1d80bf5ef75
Parents: 22b893d
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Tue Apr 26 13:48:51 2016 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Tue Apr 26 17:46:19 2016 +0200

----------------------------------------------------------------------
 .../apache/syncope/core/rest/cxf/service/AbstractAnyService.java | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/8dc9ec5f/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
index ca00e69..f58e7a0 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AbstractAnyService.java
@@ -131,7 +131,9 @@ public abstract class AbstractAnyService<TO extends AnyTO, P extends AnyPatch>
         String realm = StringUtils.prependIfMissing(searchQuery.getRealm(), SyncopeConstants.ROOT_REALM);
 
         // if an assignable query is provided in the FIQL string, start anyway from root realm
-        boolean isAssignableCond = -1 != searchQuery.getFiql().indexOf(SpecialAttr.ASSIGNABLE.toString());
+        boolean isAssignableCond = searchQuery.getFiql() == null
+                ? false
+                : -1 != searchQuery.getFiql().indexOf(SpecialAttr.ASSIGNABLE.toString());
 
         SearchCond cond = getSearchCond(searchQuery.getFiql(), realm);
         return buildPagedResult(


[2/4] syncope git commit: [SYNCOPE-790] Now binding JSON configuration to role which allows to selectively enable user / group / anyObject wizard steps, customize plain / derived / virtual attributes appearance order and even providing custom class

Posted by il...@apache.org.
http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrs.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrs.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrs.java
index b95983e..dc58bf1 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrs.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AbstractAttrs.java
@@ -20,52 +20,140 @@ package org.apache.syncope.client.console.wizards.any;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.collections4.Transformer;
 import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
 import org.apache.syncope.client.console.rest.GroupRestClient;
 import org.apache.syncope.client.console.rest.SchemaRestClient;
+import org.apache.syncope.common.lib.EntityTOUtils;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AnyTypeClassTO;
+import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.MembershipTO;
 import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.wicket.extensions.wizard.WizardStep;
+import org.apache.wicket.model.LoadableDetachableModel;
 
-public abstract class AbstractAttrs extends WizardStep {
+public abstract class AbstractAttrs<S extends AbstractSchemaTO> extends WizardStep {
 
     private static final long serialVersionUID = -5387344116983102292L;
 
-    protected final SchemaRestClient schemaRestClient = new SchemaRestClient();
+    private final SchemaRestClient schemaRestClient = new SchemaRestClient();
 
-    protected final AnyTypeClassRestClient anyTypeClassRestClient = new AnyTypeClassRestClient();
+    private final AnyTypeClassRestClient anyTypeClassRestClient = new AnyTypeClassRestClient();
 
     private final GroupRestClient groupRestClient = new GroupRestClient();
 
-    protected final AnyTO entityTO;
+    protected final AnyTO anyTO;
 
-    public AbstractAttrs(final AnyTO entityTO) {
-        this.entityTO = entityTO;
+    private final List<String> whichAttrs;
+
+    protected final Map<String, S> schemas = new LinkedHashMap<>();
+
+    protected final LoadableDetachableModel<List<AttrTO>> attrTOs;
+
+    public AbstractAttrs(final AnyTO anyTO, final List<String> anyTypeClasses, final List<String> whichAttrs) {
+        super();
+        this.setOutputMarkupId(true);
+
+        this.anyTO = anyTO;
+        this.whichAttrs = whichAttrs;
+
+        this.attrTOs = new LoadableDetachableModel<List<AttrTO>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<AttrTO> load() {
+                setSchemas(CollectionUtils.collect(anyTypeClassRestClient.list(getAllAuxClasses()),
+                        EntityTOUtils.<AnyTypeClassTO>keyTransformer(), new ArrayList<>(anyTypeClasses)));
+                setAttrs();
+                return new ArrayList<>(getAttrsFromAnyTO());
+            }
+        };
+    }
+
+    protected boolean reoderSchemas() {
+        return !whichAttrs.isEmpty();
     }
 
+    protected abstract SchemaType getSchemaType();
+
+    private void setSchemas(final List<String> anyTypeClasses) {
+        List<S> allSchemas = Collections.emptyList();
+        if (!anyTypeClasses.isEmpty()) {
+            allSchemas = schemaRestClient.getSchemas(getSchemaType(), anyTypeClasses.toArray(new String[] {}));
+        }
+
+        schemas.clear();
+
+        if (reoderSchemas()) {
+            // 1. remove attributes not selected for display
+            CollectionUtils.filter(allSchemas, new Predicate<S>() {
+
+                @Override
+                public boolean evaluate(final S schemaTO) {
+                    return whichAttrs.contains(schemaTO.getKey());
+                }
+            });
+
+            // 2. sort remainig attributes according to configuration, e.g. attrLayout
+            final Map<String, Integer> attrLayoutMap = new HashMap<>(whichAttrs.size());
+            for (int i = 0; i < whichAttrs.size(); i++) {
+                attrLayoutMap.put(whichAttrs.get(i), i);
+            }
+            Collections.sort(allSchemas, new Comparator<S>() {
+
+                @Override
+                public int compare(final S schema1, final S schema2) {
+                    int value = 0;
+
+                    if (attrLayoutMap.get(schema1.getKey()) > attrLayoutMap.get(schema2.getKey())) {
+                        value = 1;
+                    } else if (attrLayoutMap.get(schema1.getKey()) < attrLayoutMap.get(schema2.getKey())) {
+                        value = -1;
+                    }
+
+                    return value;
+                }
+            });
+        }
+        for (S schemaTO : allSchemas) {
+            schemas.put(schemaTO.getKey(), schemaTO);
+        }
+    }
+
+    protected abstract void setAttrs();
+
+    protected abstract Set<AttrTO> getAttrsFromAnyTO();
+
     protected Set<String> getAllAuxClasses() {
         final List<MembershipTO> memberships;
         final List<String> dyngroups;
-        if (entityTO instanceof UserTO) {
-            memberships = UserTO.class.cast(entityTO).getMemberships();
-            dyngroups = UserTO.class.cast(entityTO).getDynGroups();
-        } else if (entityTO instanceof AnyObjectTO) {
-            memberships = AnyObjectTO.class.cast(entityTO).getMemberships();
-            dyngroups = AnyObjectTO.class.cast(entityTO).getDynGroups();
+        if (anyTO instanceof UserTO) {
+            memberships = UserTO.class.cast(anyTO).getMemberships();
+            dyngroups = UserTO.class.cast(anyTO).getDynGroups();
+        } else if (anyTO instanceof AnyObjectTO) {
+            memberships = AnyObjectTO.class.cast(anyTO).getMemberships();
+            dyngroups = AnyObjectTO.class.cast(anyTO).getDynGroups();
         } else {
             memberships = Collections.<MembershipTO>emptyList();
             dyngroups = Collections.<String>emptyList();
         }
 
-        final List<GroupTO> groups = new ArrayList<>();
+        List<GroupTO> groups = new ArrayList<>();
         CollectionUtils.collect(memberships, new Transformer<MembershipTO, GroupTO>() {
 
             @Override
@@ -83,7 +171,7 @@ public abstract class AbstractAttrs extends WizardStep {
             }
         }, groups);
 
-        final Set<String> auxClasses = new HashSet<>(entityTO.getAuxClasses());
+        Set<String> auxClasses = new HashSet<>(anyTO.getAuxClasses());
         for (GroupTO groupTO : groups) {
             auxClasses.addAll(groupTO.getAuxClasses());
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
index 6198ce3..8a50f86 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyObjectWizardBuilder.java
@@ -21,48 +21,43 @@ package org.apache.syncope.client.console.wizards.any;
 import java.io.Serializable;
 
 import java.util.List;
-
+import org.apache.syncope.client.console.layout.AnyObjectForm;
+import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
 import org.apache.syncope.common.lib.AnyOperations;
 import org.apache.syncope.common.lib.patch.AnyObjectPatch;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 import org.apache.wicket.PageReference;
 
-public class AnyObjectWizardBuilder extends AnyWizardBuilder<AnyObjectTO> implements Serializable {
+public class AnyObjectWizardBuilder extends AnyWizardBuilder<AnyObjectTO> implements AnyObjectForm {
 
     private static final long serialVersionUID = -2480279868319546243L;
 
-    /**
-     * Construct.
-     *
-     * @param anyObjectTO any object TO.
-     * @param anyTypeClasses any type classes
-     * @param pageRef Caller page reference.
-     */
     public AnyObjectWizardBuilder(
             final AnyObjectTO anyObjectTO,
             final List<String> anyTypeClasses,
+            final AnyObjectFormLayoutInfo formLayoutInfo,
             final PageReference pageRef) {
-        super(anyObjectTO, anyTypeClasses, pageRef);
+
+        super(anyObjectTO, anyTypeClasses, formLayoutInfo, pageRef);
     }
 
     @Override
     protected Serializable onApplyInternal(final AnyHandler<AnyObjectTO> modelObject) {
         final AnyObjectTO inner = modelObject.getInnerObject();
 
-        final ProvisioningResult<AnyObjectTO> actual;
-
+        ProvisioningResult<AnyObjectTO> actual;
         if (inner.getKey() == null) {
             actual = anyObjectRestClient.create(AnyObjectTO.class.cast(inner));
         } else {
-            final AnyObjectPatch patch = AnyOperations.diff(inner, getOriginalItem().getInnerObject(), false);
+            AnyObjectPatch patch = AnyOperations.diff(inner, getOriginalItem().getInnerObject(), false);
 
-            // update user just if it is changed
-            if (!patch.isEmpty()) {
-                actual = anyObjectRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
-            } else {
+            // update just if it is changed
+            if (patch.isEmpty()) {
                 actual = new ProvisioningResult<>();
                 actual.setAny(inner);
+            } else {
+                actual = anyObjectRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
             }
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
index ae5b657..624b3f2 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AnyWizardBuilder.java
@@ -18,13 +18,15 @@
  */
 package org.apache.syncope.client.console.wizards.any;
 
-import java.io.Serializable;
-
 import java.util.Collections;
 import java.util.List;
-
 import org.apache.syncope.client.console.commons.Mode;
 import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.layout.AbstractAnyFormLayout;
+import org.apache.syncope.client.console.layout.AnyForm;
+import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
+import org.apache.syncope.client.console.layout.GroupFormLayoutInfo;
+import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
 import org.apache.syncope.client.console.rest.AnyObjectRestClient;
 import org.apache.syncope.client.console.wizards.AjaxWizardBuilder;
 import org.apache.syncope.common.lib.to.AnyTO;
@@ -34,8 +36,7 @@ import org.apache.wicket.PageReference;
 import org.apache.wicket.extensions.wizard.WizardModel;
 import org.apache.wicket.model.util.ListModel;
 
-public abstract class AnyWizardBuilder<T extends AnyTO> extends AjaxWizardBuilder<AnyHandler<T>>
-        implements Serializable {
+public abstract class AnyWizardBuilder<A extends AnyTO> extends AjaxWizardBuilder<AnyHandler<A>> {
 
     private static final long serialVersionUID = -2480279868319546243L;
 
@@ -43,16 +44,25 @@ public abstract class AnyWizardBuilder<T extends AnyTO> extends AjaxWizardBuilde
 
     protected final List<String> anyTypeClasses;
 
+    protected AbstractAnyFormLayout<A, ? extends AnyForm<A>> formLayoutInfo;
+
     /**
      * Construct.
      *
      * @param anyTO any
      * @param anyTypeClasses any type classes
-     * @param pageRef Caller page reference.
+     * @param formLayoutInfo form layout info
+     * @param pageRef caller page reference.
      */
-    public AnyWizardBuilder(final T anyTO, final List<String> anyTypeClasses, final PageReference pageRef) {
+    public AnyWizardBuilder(
+            final A anyTO,
+            final List<String> anyTypeClasses,
+            final AbstractAnyFormLayout<A, ? extends AnyForm<A>> formLayoutInfo,
+            final PageReference pageRef) {
+
         super(new AnyHandler<>(anyTO), pageRef);
         this.anyTypeClasses = anyTypeClasses;
+        this.formLayoutInfo = formLayoutInfo;
     }
 
     /**
@@ -60,54 +70,92 @@ public abstract class AnyWizardBuilder<T extends AnyTO> extends AjaxWizardBuilde
      *
      * @param handler any handler
      * @param anyTypeClasses any type classes
-     * @param pageRef Caller page reference.
+     * @param formLayoutInfo form layout info
+     * @param pageRef caller page reference.
      */
     public AnyWizardBuilder(
-            final AnyHandler<T> handler,
+            final AnyHandler<A> handler,
             final List<String> anyTypeClasses,
+            final AbstractAnyFormLayout<A, ? extends AnyForm<A>> formLayoutInfo,
             final PageReference pageRef) {
+
         super(handler, pageRef);
         this.anyTypeClasses = anyTypeClasses;
+        this.formLayoutInfo = formLayoutInfo;
     }
 
     @Override
-    protected WizardModel buildModelSteps(final AnyHandler<T> modelObject, final WizardModel wizardModel) {
-        final String[] clazzes = anyTypeClasses.toArray(new String[] {});
+    protected WizardModel buildModelSteps(final AnyHandler<A> modelObject, final WizardModel wizardModel) {
         // optional details panel step
         addOptionalDetailsPanel(modelObject, wizardModel);
 
-        if ((this instanceof GroupWizardBuilder) && (modelObject.getInnerObject() instanceof GroupTO)) {
-            wizardModel.add(new Ownership(GroupHandler.class.cast(modelObject), pageRef));
-            wizardModel.add(new DynamicMemberships(GroupHandler.class.cast(modelObject)));
+        if ((this instanceof GroupWizardBuilder)
+                && (modelObject.getInnerObject() instanceof GroupTO)
+                && (formLayoutInfo instanceof GroupFormLayoutInfo)) {
+
+            GroupFormLayoutInfo groupFormLayoutInfo = GroupFormLayoutInfo.class.cast(formLayoutInfo);
+            if (groupFormLayoutInfo.isOwnership()) {
+                wizardModel.add(new Ownership(GroupHandler.class.cast(modelObject), pageRef));
+            }
+            if (groupFormLayoutInfo.isDynamicMemberships()) {
+                wizardModel.add(new DynamicMemberships(GroupHandler.class.cast(modelObject)));
+            }
         }
 
-        wizardModel.add(new AuxClasses(modelObject.getInnerObject(), clazzes));
+        if (formLayoutInfo.isAuxClasses()) {
+            wizardModel.add(new AuxClasses(modelObject.getInnerObject(), anyTypeClasses));
+        }
 
         // attributes panel steps
-        wizardModel.add(new PlainAttrs(modelObject.getInnerObject(), null, Mode.ADMIN, clazzes));
-        wizardModel.add(new DerAttrs(modelObject.getInnerObject(), clazzes));
-        wizardModel.add(new VirAttrs(modelObject.getInnerObject(), clazzes));
+        if (formLayoutInfo.isPlainAttrs()) {
+            wizardModel.add(new PlainAttrs(
+                    modelObject.getInnerObject(),
+                    null,
+                    Mode.ADMIN,
+                    anyTypeClasses,
+                    formLayoutInfo.getWhichPlainAttrs()));
+        }
+        if (formLayoutInfo.isDerAttrs()) {
+            wizardModel.add(new DerAttrs(
+                    modelObject.getInnerObject(), anyTypeClasses, formLayoutInfo.getWhichDerAttrs()));
+        }
+        if (formLayoutInfo.isVirAttrs()) {
+            wizardModel.add(new VirAttrs(
+                    modelObject.getInnerObject(), anyTypeClasses, formLayoutInfo.getWhichVirAttrs()));
+        }
+
+        // role panel step (just available for users)
+        if ((this instanceof UserWizardBuilder)
+                && (modelObject.getInnerObject() instanceof UserTO)
+                && (formLayoutInfo instanceof UserFormLayoutInfo)
+                && UserFormLayoutInfo.class.cast(formLayoutInfo).isRoles()) {
 
-        // role panel step (jst available for users)
-        if ((this instanceof UserWizardBuilder) && (modelObject.getInnerObject() instanceof UserTO)) {
             wizardModel.add(new Roles(UserTO.class.cast(modelObject.getInnerObject())));
         }
 
-        // relationship panel step (jst available for users)
-        if (!(this instanceof GroupWizardBuilder)) {
+        // relationship panel step (available for users and any objects)
+        if (((formLayoutInfo instanceof UserFormLayoutInfo)
+                && UserFormLayoutInfo.class.cast(formLayoutInfo).isRelationships())
+                || ((formLayoutInfo instanceof AnyObjectFormLayoutInfo)
+                && AnyObjectFormLayoutInfo.class.cast(formLayoutInfo).isRelationships())) {
+
             wizardModel.add(new Relationships(modelObject.getInnerObject(), pageRef));
         }
 
         // resource panel step
-        wizardModel.add(new Resources(modelObject.getInnerObject()));
+        if (formLayoutInfo.isResources()) {
+            wizardModel.add(new Resources(modelObject.getInnerObject()));
+        }
+
         return wizardModel;
     }
 
-    protected AnyWizardBuilder<T> addOptionalDetailsPanel(
-            final AnyHandler<T> modelObject, final WizardModel wizardModel) {
+    protected AnyWizardBuilder<A> addOptionalDetailsPanel(
+            final AnyHandler<A> modelObject, final WizardModel wizardModel) {
+
         if (modelObject.getInnerObject().getKey() != null) {
             wizardModel.add(new Details<>(
-                    modelObject, new ListModel<>(Collections.<StatusBean>emptyList()), pageRef, true));
+                    modelObject, new ListModel<>(Collections.<StatusBean>emptyList()), true, pageRef));
         }
         return this;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AuxClasses.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AuxClasses.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AuxClasses.java
index 47e6669..b70a1c0 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AuxClasses.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/AuxClasses.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.client.console.wizards.any;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import org.apache.commons.collections4.CollectionUtils;
@@ -47,7 +46,7 @@ public class AuxClasses extends WizardStep {
 
     private final GroupRestClient groupRestClient = new GroupRestClient();
 
-    public <T extends AnyTO> AuxClasses(final T entityTO, final String... anyTypeClass) {
+    public <T extends AnyTO> AuxClasses(final T entityTO, final List<String> anyTypeClasses) {
         this.setOutputMarkupId(true);
 
         final Fragment fragment;
@@ -98,7 +97,7 @@ public class AuxClasses extends WizardStep {
                     "groups", new ListModel<>(memberships),
                     new AjaxPalettePanel.Builder.Query<MembershipTO>() {
 
-                private static final long serialVersionUID = 1L;
+                private static final long serialVersionUID = -7223078772249308813L;
 
                 @Override
                 public List<MembershipTO> execute(final String filter) {
@@ -142,11 +141,9 @@ public class AuxClasses extends WizardStep {
         }
         add(fragment);
 
-        final List<String> current = Arrays.asList(anyTypeClass);
-
         final List<String> choices = new ArrayList<>();
         for (AnyTypeClassTO aux : new AnyTypeClassRestClient().list()) {
-            if (!current.contains(aux.getKey())) {
+            if (!anyTypeClasses.contains(aux.getKey())) {
                 choices.add(aux.getKey());
             }
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/DerAttrs.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/DerAttrs.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/DerAttrs.java
index b5e8374..c8ccfee 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/DerAttrs.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/DerAttrs.java
@@ -19,17 +19,12 @@
 package org.apache.syncope.client.console.wizards.any;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
+import java.util.Set;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
-import org.apache.syncope.common.lib.EntityTOUtils;
 import org.apache.syncope.common.lib.to.AnyTO;
-import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.DerSchemaTO;
 import org.apache.syncope.common.lib.types.SchemaType;
@@ -37,70 +32,31 @@ import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.MarkupStream;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
-import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
 import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.LoadableDetachableModel;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.model.ResourceModel;
 
-public class DerAttrs extends AbstractAttrs {
+public class DerAttrs extends AbstractAttrs<DerSchemaTO> {
 
     private static final long serialVersionUID = -5387344116983102292L;
 
-    public <T extends AnyTO> DerAttrs(final T entityTO, final String... anyTypeClass) {
-        super(entityTO);
-        setOutputMarkupId(true);
+    public <T extends AnyTO> DerAttrs(
+            final T anyTO,
+            final List<String> anyTypeClasses,
+            final List<String> whichDerAttrs) {
 
-        final LoadableDetachableModel<List<AttrTO>> derAttrTOs = new LoadableDetachableModel<List<AttrTO>>() {
+        super(anyTO, anyTypeClasses, whichDerAttrs);
 
-            private static final long serialVersionUID = 5275935387613157437L;
-
-            @Override
-            protected List<AttrTO> load() {
-                List<String> anyTypeClasses = CollectionUtils.collect(anyTypeClassRestClient.list(getAllAuxClasses()),
-                        EntityTOUtils.<AnyTypeClassTO>keyTransformer(), new ArrayList<>(Arrays.asList(anyTypeClass)));
-
-                List<DerSchemaTO> derSchemas = Collections.emptyList();
-                if (!anyTypeClasses.isEmpty()) {
-                    derSchemas =
-                            schemaRestClient.getSchemas(SchemaType.DERIVED, anyTypeClasses.toArray(new String[] {}));
-                }
-
-                final Map<String, AttrTO> currents = entityTO.getDerAttrMap();
-                entityTO.getDerAttrs().clear();
-
-                // This conversion from set to lis is required by the ListView.
-                // Not performed by using collect parameter because entityTO change is required.
-                return new ArrayList<>(
-                        CollectionUtils.collect(derSchemas, new Transformer<DerSchemaTO, AttrTO>() {
-
-                            @Override
-                            public AttrTO transform(final DerSchemaTO input) {
-                                AttrTO attrTO = currents.get(input.getKey());
-                                if (attrTO == null) {
-                                    attrTO = new AttrTO();
-                                    attrTO.setSchema(input.getKey());
-                                }
-                                return attrTO;
-                            }
-                        }, entityTO.getDerAttrs()));
-            }
-        };
-
-        final WebMarkupContainer attributesContainer = new WebMarkupContainer("derAttrContainer");
-        attributesContainer.setOutputMarkupId(true);
-        add(attributesContainer);
-
-        ListView<AttrTO> attributes = new ListView<AttrTO>("attrs", derAttrTOs) {
+        add(new ListView<AttrTO>("schemas", attrTOs) {
 
             private static final long serialVersionUID = 9101744072914090143L;
 
             @Override
             public void renderHead(final IHeaderResponse response) {
                 super.renderHead(response);
-                if (derAttrTOs.getObject().isEmpty()) {
+                if (attrTOs.getObject().isEmpty()) {
                     response.render(OnDomReadyHeaderItem.forScript(
                             String.format("$('#emptyPlaceholder').append(\"%s\")", getString("attribute.empty.list"))));
                 }
@@ -114,26 +70,53 @@ public class DerAttrs extends AbstractAttrs {
 
             @Override
             protected void populateItem(final ListItem<AttrTO> item) {
-                final AttrTO attrTO = item.getModelObject();
+                AttrTO attrTO = item.getModelObject();
 
-                final IModel<String> model;
-                final List<String> values = attrTO.getValues();
+                IModel<String> model;
+                List<String> values = attrTO.getValues();
                 if (values == null || values.isEmpty()) {
                     model = new ResourceModel("derived.emptyvalue.message", StringUtils.EMPTY);
                 } else {
                     model = new Model<>(values.get(0));
                 }
 
-                final AjaxTextFieldPanel panel = new AjaxTextFieldPanel(
-                        "panel", attrTO.getSchema(), model, false);
-
+                AjaxTextFieldPanel panel = new AjaxTextFieldPanel("panel", attrTO.getSchema(), model, false);
                 panel.setEnabled(false);
                 panel.setRequired(true);
                 panel.setOutputMarkupId(true);
                 item.add(panel);
+            }
+        });
+    }
 
+    @Override
+    protected SchemaType getSchemaType() {
+        return SchemaType.DERIVED;
+    }
+
+    @Override
+    protected Set<AttrTO> getAttrsFromAnyTO() {
+        return anyTO.getDerAttrs();
+    }
+
+    @Override
+    protected void setAttrs() {
+        List<AttrTO> attrs = new ArrayList<>();
+
+        Map<String, AttrTO> attrMap = anyTO.getDerAttrMap();
+
+        for (DerSchemaTO schema : schemas.values()) {
+            AttrTO attrTO = new AttrTO();
+            attrTO.setSchema(schema.getKey());
+            if (attrMap.containsKey(schema.getKey())) {
+                attrTO.getValues().addAll(attrMap.get(schema.getKey()).getValues());
             }
-        };
-        attributesContainer.add(attributes);
+
+            attrs.add(attrTO);
+        }
+
+        anyTO.getDerAttrs().clear();
+        anyTO.getDerAttrs().addAll(attrs);
     }
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
index 8d18d45..41a5573 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Details.java
@@ -40,8 +40,9 @@ public class Details<T extends AnyTO> extends WizardStep {
     public Details(
             final AnyHandler<T> handler,
             final IModel<List<StatusBean>> statusModel,
-            final PageReference pageRef,
-            final boolean includeStatusPanel) {
+            final boolean includeStatusPanel,
+            final PageReference pageRef) {
+
         this.pageRef = pageRef;
 
         T anyTO = handler.getInnerObject();

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
index 8595b19..610f2b8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupDetails.java
@@ -34,15 +34,15 @@ public class GroupDetails extends Details<GroupTO> {
             final GroupHandler groupHandler,
             final IModel<List<StatusBean>> statusModel,
             final boolean templateMode,
-            final PageReference pageRef,
-            final boolean includeStatusPanel) {
-        super(groupHandler, statusModel, pageRef, includeStatusPanel);
+            final boolean includeStatusPanel,
+            final PageReference pageRef) {
+
+        super(groupHandler, statusModel, includeStatusPanel, pageRef);
 
         final GroupTO groupTO = GroupHandler.class.cast(groupHandler).getInnerObject();
 
         final AjaxTextFieldPanel name = new AjaxTextFieldPanel("name", "name",
                 new PropertyModel<String>(groupTO, "name"), false);
-
         if (!templateMode) {
             name.addRequiredLabel();
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupWizardBuilder.java
index e45afa4..e9fe94b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/GroupWizardBuilder.java
@@ -22,6 +22,8 @@ import java.io.Serializable;
 import java.util.Collections;
 import java.util.List;
 import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.layout.GroupForm;
+import org.apache.syncope.client.console.layout.GroupFormLayoutInfo;
 import org.apache.syncope.client.console.rest.GroupRestClient;
 import org.apache.syncope.client.console.wizards.AjaxWizardBuilder;
 import org.apache.syncope.common.lib.AnyOperations;
@@ -32,21 +34,19 @@ import org.apache.wicket.PageReference;
 import org.apache.wicket.extensions.wizard.WizardModel;
 import org.apache.wicket.model.util.ListModel;
 
-public class GroupWizardBuilder extends AnyWizardBuilder<GroupTO> {
+public class GroupWizardBuilder extends AnyWizardBuilder<GroupTO> implements GroupForm {
 
     private static final long serialVersionUID = 5945391813567245081L;
 
     private final GroupRestClient groupRestClient = new GroupRestClient();
 
-    /**
-     * Construct.
-     *
-     * @param groupTO any
-     * @param anyTypeClasses any type classes
-     * @param pageRef Caller page reference.
-     */
-    public GroupWizardBuilder(final GroupTO groupTO, final List<String> anyTypeClasses, final PageReference pageRef) {
-        super(new GroupHandler(groupTO), anyTypeClasses, pageRef);
+    public GroupWizardBuilder(
+            final GroupTO groupTO,
+            final List<String> anyTypeClasses,
+            final GroupFormLayoutInfo formLayoutInfo,
+            final PageReference pageRef) {
+
+        super(new GroupHandler(groupTO), anyTypeClasses, formLayoutInfo, pageRef);
     }
 
     /**
@@ -65,22 +65,21 @@ public class GroupWizardBuilder extends AnyWizardBuilder<GroupTO> {
 
     @Override
     protected Serializable onApplyInternal(final AnyHandler<GroupTO> modelObject) {
-        final ProvisioningResult<GroupTO> actual;
-
-        GroupTO toBeProcessed = modelObject instanceof GroupHandler
+        GroupTO inner = modelObject instanceof GroupHandler
                 ? GroupHandler.class.cast(modelObject).fillDynamicConditions()
                 : modelObject.getInnerObject();
 
-        if (toBeProcessed.getKey() == null) {
-            actual = groupRestClient.create(toBeProcessed);
+        ProvisioningResult<GroupTO> actual;
+        if (inner.getKey() == null) {
+            actual = groupRestClient.create(inner);
         } else {
-            final GroupPatch patch = AnyOperations.diff(toBeProcessed, getOriginalItem().getInnerObject(), false);
-            // update user just if it is changed
-            if (!patch.isEmpty()) {
-                actual = groupRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
-            } else {
+            GroupPatch patch = AnyOperations.diff(inner, getOriginalItem().getInnerObject(), false);
+            // update just if it is changed
+            if (patch.isEmpty()) {
                 actual = new ProvisioningResult<>();
-                actual.setAny(toBeProcessed);
+                actual.setAny(inner);
+            } else {
+                actual = groupRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
             }
         }
 
@@ -93,8 +92,8 @@ public class GroupWizardBuilder extends AnyWizardBuilder<GroupTO> {
         wizardModel.add(new GroupDetails(
                 GroupHandler.class.cast(modelObject),
                 new ListModel<>(Collections.<StatusBean>emptyList()),
-                false, pageRef,
-                modelObject.getInnerObject().getKey() != null));
+                false,
+                modelObject.getInnerObject().getKey() != null, pageRef));
         return this;
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
index 6c17cdd..dc2b5c2 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/PlainAttrs.java
@@ -19,15 +19,10 @@
 package org.apache.syncope.client.console.wizards.any;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import org.apache.commons.collections4.CollectionUtils;
+import java.util.Set;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.commons.Mode;
 import org.apache.syncope.client.console.commons.SchemaUtils;
@@ -40,10 +35,8 @@ import org.apache.syncope.client.console.wicket.markup.html.form.DateTextFieldPa
 import org.apache.syncope.client.console.wicket.markup.html.form.DateTimeFieldPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.FieldPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
-import org.apache.syncope.common.lib.EntityTOUtils;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.AnyTO;
-import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.PlainSchemaTO;
 import org.apache.syncope.common.lib.types.AttrSchemaType;
@@ -55,46 +48,33 @@ import org.apache.wicket.markup.html.form.IChoiceRenderer;
 import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
 import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.LoadableDetachableModel;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.model.PropertyModel;
 
-public class PlainAttrs extends AbstractAttrs {
+public class PlainAttrs extends AbstractAttrs<PlainSchemaTO> {
 
     private static final long serialVersionUID = 552437609667518888L;
 
     private final Mode mode;
 
-    private Map<String, PlainSchemaTO> schemas = new LinkedHashMap<>();
-
     public <T extends AnyTO> PlainAttrs(
-            final T entityTO, final Form<?> form, final Mode mode, final String... anyTypeClass) {
-        super(entityTO);
-        this.setOutputMarkupId(true);
+            final T anyTO,
+            final Form<?> form,
+            final Mode mode,
+            final List<String> anyTypeClasses,
+            final List<String> whichPlainAttrs) {
 
+        super(anyTO, anyTypeClasses, whichPlainAttrs);
         this.mode = mode;
 
-        final LoadableDetachableModel<List<AttrTO>> plainAttrTOs = new LoadableDetachableModel<List<AttrTO>>() {
-
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            protected List<AttrTO> load() {
-                setPlainSchemas(CollectionUtils.collect(anyTypeClassRestClient.list(getAllAuxClasses()),
-                        EntityTOUtils.<AnyTypeClassTO>keyTransformer(), new ArrayList<>(Arrays.asList(anyTypeClass))));
-                setAttrs();
-                return new ArrayList<>(entityTO.getPlainAttrs());
-            }
-        };
-
-        add(new ListView<AttrTO>("schemas", plainAttrTOs) {
+        add(new ListView<AttrTO>("schemas", attrTOs) {
 
             private static final long serialVersionUID = 9101744072914090143L;
 
             @Override
             public void renderHead(final IHeaderResponse response) {
                 super.renderHead(response);
-                if (plainAttrTOs.getObject().isEmpty()) {
+                if (attrTOs.getObject().isEmpty()) {
                     response.render(OnDomReadyHeaderItem.forScript(
                             String.format("$('#emptyPlaceholder').append(\"%s\")", getString("attribute.empty.list"))));
                 }
@@ -103,105 +83,82 @@ public class PlainAttrs extends AbstractAttrs {
             @Override
             @SuppressWarnings({ "unchecked", "rawtypes" })
             protected void populateItem(final ListItem<AttrTO> item) {
-                final AttrTO attributeTO = (AttrTO) item.getDefaultModelObject();
-
-                final FieldPanel panel = getFieldPanel(schemas.get(attributeTO.getSchema()));
+                AttrTO attrTO = item.getModelObject();
 
-                if (mode == Mode.TEMPLATE || !schemas.get(attributeTO.getSchema()).isMultivalue()) {
+                FieldPanel panel = getFieldPanel(schemas.get(attrTO.getSchema()));
+                if (mode == Mode.TEMPLATE || !schemas.get(attrTO.getSchema()).isMultivalue()) {
                     item.add(panel);
-                    panel.setNewModel(attributeTO.getValues());
+                    panel.setNewModel(attrTO.getValues());
                 } else {
                     item.add(new MultiFieldPanel.Builder<>(
-                            new PropertyModel<List<String>>(attributeTO, "values")).build(
+                            new PropertyModel<List<String>>(attrTO, "values")).build(
                             "panel",
-                            attributeTO.getSchema(),
+                            attrTO.getSchema(),
                             panel));
                 }
             }
         });
     }
 
-    private void setPlainSchemas(final List<String> anyTypeClasses) {
-        List<PlainSchemaTO> plainSchemas = Collections.emptyList();
-        if (!anyTypeClasses.isEmpty()) {
-            plainSchemas = schemaRestClient.getSchemas(SchemaType.PLAIN, anyTypeClasses.toArray(new String[] {}));
-        }
-
-        schemas.clear();
-
-        // SYNCOPE-790
-        AttrTO attrLayout = null;
-        if (attrLayout != null && mode != Mode.TEMPLATE) {
-            // 1. remove attributes not selected for display
-            schemaRestClient.filter(plainSchemas, attrLayout.getValues(), true);
-            // 2. sort remainig attributes according to configuration, e.g. attrLayout
-            final Map<String, Integer> attrLayoutMap = new HashMap<>(attrLayout.getValues().size());
-            for (int i = 0; i < attrLayout.getValues().size(); i++) {
-                attrLayoutMap.put(attrLayout.getValues().get(i), i);
-            }
-            Collections.sort(plainSchemas, new Comparator<PlainSchemaTO>() {
-
-                @Override
-                public int compare(final PlainSchemaTO schema1, final PlainSchemaTO schema2) {
-                    int value = 0;
+    @Override
+    protected SchemaType getSchemaType() {
+        return SchemaType.PLAIN;
+    }
 
-                    if (attrLayoutMap.get(schema1.getKey()) > attrLayoutMap.get(schema2.getKey())) {
-                        value = 1;
-                    } else if (attrLayoutMap.get(schema1.getKey()) < attrLayoutMap.get(schema2.getKey())) {
-                        value = -1;
-                    }
+    @Override
+    protected boolean reoderSchemas() {
+        return super.reoderSchemas() && mode != Mode.TEMPLATE;
+    }
 
-                    return value;
-                }
-            });
-        }
-        for (PlainSchemaTO schemaTO : plainSchemas) {
-            schemas.put(schemaTO.getKey(), schemaTO);
-        }
+    @Override
+    protected Set<AttrTO> getAttrsFromAnyTO() {
+        return anyTO.getPlainAttrs();
     }
 
-    private void setAttrs() {
-        final List<AttrTO> entityData = new ArrayList<>();
+    @Override
+    protected void setAttrs() {
+        List<AttrTO> attrs = new ArrayList<>();
 
-        final Map<String, AttrTO> attrMap = entityTO.getPlainAttrMap();
+        Map<String, AttrTO> attrMap = anyTO.getPlainAttrMap();
 
         for (PlainSchemaTO schema : schemas.values()) {
-            final AttrTO attributeTO = new AttrTO();
-            attributeTO.setSchema(schema.getKey());
+            AttrTO attrTO = new AttrTO();
+            attrTO.setSchema(schema.getKey());
 
             if (attrMap.get(schema.getKey()) == null || attrMap.get(schema.getKey()).getValues().isEmpty()) {
-                attributeTO.getValues().add("");
+                attrTO.getValues().add("");
 
                 // is important to set readonly only after values setting
-                attributeTO.setReadonly(schema.isReadonly());
+                attrTO.setReadonly(schema.isReadonly());
             } else {
-                attributeTO.getValues().addAll(attrMap.get(schema.getKey()).getValues());
+                attrTO.getValues().addAll(attrMap.get(schema.getKey()).getValues());
             }
-            entityData.add(attributeTO);
+            attrs.add(attrTO);
         }
 
-        entityTO.getPlainAttrs().clear();
-        entityTO.getPlainAttrs().addAll(entityData);
+        anyTO.getPlainAttrs().clear();
+        anyTO.getPlainAttrs().addAll(attrs);
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
     private FieldPanel getFieldPanel(final PlainSchemaTO schemaTO) {
-        final boolean required = mode == Mode.TEMPLATE
+        boolean required = mode == Mode.TEMPLATE
                 ? false
                 : schemaTO.getMandatoryCondition().equalsIgnoreCase("true");
 
-        final boolean readOnly = mode == Mode.TEMPLATE ? false : schemaTO.isReadonly();
+        boolean readOnly = mode == Mode.TEMPLATE ? false : schemaTO.isReadonly();
 
-        final AttrSchemaType type = mode == Mode.TEMPLATE ? AttrSchemaType.String : schemaTO.getType();
+        AttrSchemaType type = mode == Mode.TEMPLATE ? AttrSchemaType.String : schemaTO.getType();
 
-        final FieldPanel panel;
+        FieldPanel panel;
         switch (type) {
             case Boolean:
                 panel = new AjaxCheckBoxPanel("panel", schemaTO.getKey(), new Model<Boolean>(), false);
                 panel.setRequired(required);
                 break;
+
             case Date:
-                final String dataPattern = schemaTO.getConversionPattern() == null
+                String dataPattern = schemaTO.getConversionPattern() == null
                         ? SyncopeConstants.DEFAULT_DATE_PATTERN
                         : schemaTO.getConversionPattern();
 
@@ -216,6 +173,7 @@ public class PlainAttrs extends AbstractAttrs {
                 }
 
                 break;
+
             case Enum:
                 panel = new AjaxDropDownChoicePanel<>("panel", schemaTO.getKey(), new Model<String>(), false);
                 ((AjaxDropDownChoicePanel<String>) panel).setChoices(SchemaUtils.getEnumeratedValues(schemaTO));

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Roles.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Roles.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Roles.java
index 594ea44..c80247e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Roles.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/Roles.java
@@ -38,7 +38,7 @@ public class Roles extends WizardStep {
     public <T extends AnyTO> Roles(final UserTO entityTO) {
         this.setOutputMarkupId(true);
 
-        final ArrayList<String> allRoles = CollectionUtils.collect(new RoleRestClient().getAll(),
+        final ArrayList<String> allRoles = CollectionUtils.collect(new RoleRestClient().list(),
                 EntityTOUtils.<RoleTO>keyTransformer(), new ArrayList<String>());
 
         add(new AjaxPalettePanel.Builder<String>().build("roles",

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserDetails.java
index b6e071d..28a7d91 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserDetails.java
@@ -50,9 +50,11 @@ public class UserDetails extends Details<UserTO> {
             final IModel<List<StatusBean>> statusModel,
             final boolean resetPassword,
             final boolean templateMode,
-            final PageReference pageRef,
-            final boolean includeStatusPanel) {
-        super(handler, statusModel, pageRef, includeStatusPanel);
+            final boolean includeStatusPanel,
+            final boolean showPasswordManagement,
+            final PageReference pageRef) {
+
+        super(handler, statusModel, includeStatusPanel, pageRef);
 
         final UserTO userTO = handler.getInnerObject();
         // ------------------------
@@ -86,7 +88,7 @@ public class UserDetails extends Details<UserTO> {
         }
         ), model) {
 
-            private static final long serialVersionUID = 1L;
+            private static final long serialVersionUID = -2898628183677758699L;
 
             @Override
             protected Component newTitle(final String markupId, final ITab tab, final Accordion.State state) {
@@ -119,6 +121,7 @@ public class UserDetails extends Details<UserTO> {
         };
 
         accordion.setOutputMarkupId(true);
+        accordion.setVisible(showPasswordManagement);
         add(accordion);
         // ------------------------        
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserInformationPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserInformationPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserInformationPanel.java
index 033bf40..192a74e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserInformationPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserInformationPanel.java
@@ -35,7 +35,7 @@ public class UserInformationPanel extends AnnotatedBeanPanel {
         // ------------------------
         // Change password date
         // ------------------------
-        add(new Label("changePwdDate", new Model<String>(userTO.getChangePwdDate() == null
+        add(new Label("changePwdDate", new Model<>(userTO.getChangePwdDate() == null
                 ? StringUtils.EMPTY
                 : SyncopeConsoleSession.get().getDateFormat().format(userTO.getChangePwdDate()))));
         // ------------------------
@@ -43,7 +43,7 @@ public class UserInformationPanel extends AnnotatedBeanPanel {
         // ------------------------
         // Last login date
         // ------------------------
-        add(new Label("lastLoginDate", new Model<String>(userTO.getLastLoginDate() == null
+        add(new Label("lastLoginDate", new Model<>(userTO.getLastLoginDate() == null
                 ? StringUtils.EMPTY
                 : SyncopeConsoleSession.get().getDateFormat().format(userTO.getLastLoginDate()))));
         // ------------------------
@@ -51,13 +51,13 @@ public class UserInformationPanel extends AnnotatedBeanPanel {
         // ------------------------
         // Failed logins
         // ------------------------
-        add(new Label("failedLogins", new Model<Integer>(userTO.getFailedLogins())));
+        add(new Label("failedLogins", new Model<>(userTO.getFailedLogins())));
         // ------------------------
 
         // ------------------------
         // Token
         // ------------------------
-        add(new Label("token", new Model<String>(userTO.getToken() == null
+        add(new Label("token", new Model<>(userTO.getToken() == null
                 ? StringUtils.EMPTY
                 : userTO.getToken())));
         // ------------------------
@@ -65,7 +65,7 @@ public class UserInformationPanel extends AnnotatedBeanPanel {
         // ------------------------
         // Token expire time
         // ------------------------
-        add(new Label("tokenExpireTime", new Model<String>(userTO.getTokenExpireTime() == null
+        add(new Label("tokenExpireTime", new Model<>(userTO.getTokenExpireTime() == null
                 ? StringUtils.EMPTY
                 : SyncopeConsoleSession.get().getDateFormat().format(userTO.getTokenExpireTime()))));
         // ------------------------

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
index eb1d490..2f8b5f6 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/UserWizardBuilder.java
@@ -24,6 +24,8 @@ import java.util.List;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.commons.status.StatusBean;
 import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.client.console.layout.UserForm;
+import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
 import org.apache.syncope.client.console.rest.UserRestClient;
 import org.apache.syncope.common.lib.AnyOperations;
 import org.apache.syncope.common.lib.patch.UserPatch;
@@ -34,7 +36,7 @@ import org.apache.wicket.extensions.wizard.WizardModel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.util.ListModel;
 
-public class UserWizardBuilder extends AnyWizardBuilder<UserTO> {
+public class UserWizardBuilder extends AnyWizardBuilder<UserTO> implements UserForm {
 
     private static final long serialVersionUID = 6716803168859873877L;
 
@@ -42,27 +44,21 @@ public class UserWizardBuilder extends AnyWizardBuilder<UserTO> {
 
     private final IModel<List<StatusBean>> statusModel;
 
-    /**
-     * Construct.
-     *
-     * @param userTO any
-     * @param anyTypeClasses any type classes
-     * @param pageRef Caller page reference.
-     */
     public UserWizardBuilder(
             final UserTO userTO,
             final List<String> anyTypeClasses,
+            final UserFormLayoutInfo formLayoutInfo,
             final PageReference pageRef) {
-        super(userTO, anyTypeClasses, pageRef);
+
+        super(userTO, anyTypeClasses, formLayoutInfo, pageRef);
         statusModel = new ListModel<>(new ArrayList<StatusBean>());
     }
 
     @Override
     protected Serializable onApplyInternal(final AnyHandler<UserTO> modelObject) {
-        final ProvisioningResult<UserTO> actual;
-
-        final UserTO inner = modelObject.getInnerObject();
+        UserTO inner = modelObject.getInnerObject();
 
+        ProvisioningResult<UserTO> actual;
         if (inner.getKey() == null) {
             actual = userRestClient.create(inner, StringUtils.isNotBlank(inner.getPassword()));
         } else {
@@ -71,12 +67,12 @@ public class UserWizardBuilder extends AnyWizardBuilder<UserTO> {
                 patch.setPassword(StatusUtils.buildPasswordPatch(inner.getPassword(), statusModel.getObject()));
             }
 
-            // update user just if it is changed
-            if (!patch.isEmpty()) {
-                actual = userRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
-            } else {
+            // update just if it is changed
+            if (patch.isEmpty()) {
                 actual = new ProvisioningResult<>();
                 actual.setAny(inner);
+            } else {
+                actual = userRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
             }
         }
 
@@ -88,8 +84,10 @@ public class UserWizardBuilder extends AnyWizardBuilder<UserTO> {
             final AnyHandler<UserTO> modelObject, final WizardModel wizardModel) {
 
         wizardModel.add(new UserDetails(
-                modelObject, statusModel, false, false, pageRef,
-                modelObject.getInnerObject().getKey() != null));
+                modelObject, statusModel, false, false,
+                modelObject.getInnerObject().getKey() != null,
+                UserFormLayoutInfo.class.cast(formLayoutInfo).isPasswordManagement(),
+                pageRef));
         return this;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/VirAttrs.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/VirAttrs.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/VirAttrs.java
index f5dab16..21b7b9a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/VirAttrs.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/any/VirAttrs.java
@@ -19,90 +19,42 @@
 package org.apache.syncope.client.console.wizards.any;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.collections4.Transformer;
+import java.util.Set;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
 import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
-import org.apache.syncope.common.lib.EntityTOUtils;
 import org.apache.syncope.common.lib.to.AnyTO;
-import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.VirSchemaTO;
 import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
-import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
-import org.apache.wicket.model.LoadableDetachableModel;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.model.PropertyModel;
 
-public class VirAttrs extends AbstractAttrs {
+public class VirAttrs extends AbstractAttrs<VirSchemaTO> {
 
     private static final long serialVersionUID = -7982691107029848579L;
 
-    public <T extends AnyTO> VirAttrs(final T entityTO, final String... anyTypeClass) {
-        super(entityTO);
-        this.setOutputMarkupId(true);
+    public <T extends AnyTO> VirAttrs(
+            final T anyTO,
+            final List<String> anyTypeClasses,
+            final List<String> whichVirAttrs) {
 
-        final LoadableDetachableModel<List<AttrTO>> virAttrTOs = new LoadableDetachableModel<List<AttrTO>>() {
+        super(anyTO, anyTypeClasses, whichVirAttrs);
 
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            protected List<AttrTO> load() {
-                List<String> anyTypeClasses = CollectionUtils.collect(anyTypeClassRestClient.list(getAllAuxClasses()),
-                        EntityTOUtils.<AnyTypeClassTO>keyTransformer(), new ArrayList<>(Arrays.asList(anyTypeClass)));
-
-                List<VirSchemaTO> virSchemas = Collections.emptyList();
-                if (!anyTypeClasses.isEmpty()) {
-                    virSchemas =
-                            schemaRestClient.getSchemas(SchemaType.VIRTUAL, anyTypeClasses.toArray(new String[] {}));
-                }
-
-                final Map<String, AttrTO> currents = entityTO.getVirAttrMap();
-                entityTO.getVirAttrs().clear();
-
-                // This conversion from set to lis is required by the ListView.
-                // Not performed by using collect parameter because entityTO change is required.
-                return new ArrayList<>(CollectionUtils.collect(virSchemas, new Transformer<VirSchemaTO, AttrTO>() {
-
-                    @Override
-                    public AttrTO transform(final VirSchemaTO input) {
-                        AttrTO attrTO = currents.get(input.getKey());
-                        if (attrTO == null) {
-                            attrTO = new AttrTO();
-                            attrTO.setSchema(input.getKey());
-                            attrTO.getValues().add(StringUtils.EMPTY);
-                        } else if (attrTO.getValues().isEmpty()) {
-                            attrTO.getValues().add("");
-                        }
-
-                        attrTO.setReadonly(input.isReadonly());
-                        return attrTO;
-                    }
-                }, entityTO.getVirAttrs()));
-            }
-        };
-
-        final WebMarkupContainer attributesContainer = new WebMarkupContainer("virAttrContainer");
-        attributesContainer.setOutputMarkupId(true);
-        add(attributesContainer);
-
-        ListView<AttrTO> attributes = new ListView<AttrTO>("attrs", virAttrTOs) {
+        add(new ListView<AttrTO>("schemas", attrTOs) {
 
             private static final long serialVersionUID = 9101744072914090143L;
 
             @Override
             public void renderHead(final IHeaderResponse response) {
                 super.renderHead(response);
-                if (virAttrTOs.getObject().isEmpty()) {
+                if (attrTOs.getObject().isEmpty()) {
                     response.render(OnDomReadyHeaderItem.forScript(
                             String.format("$('#emptyPlaceholder').append(\"%s\")", getString("attribute.empty.list"))));
                 }
@@ -115,17 +67,46 @@ public class VirAttrs extends AbstractAttrs {
 
                 attrTO.setReadonly(attrTO.isReadonly());
 
-                final AjaxTextFieldPanel panel = new AjaxTextFieldPanel(
+                AjaxTextFieldPanel panel = new AjaxTextFieldPanel(
                         "panel", attrTO.getSchema(), new Model<String>(), false);
-
                 item.add(new MultiFieldPanel.Builder<>(
                         new PropertyModel<List<String>>(attrTO, "values")).build(
                         "panel",
                         attrTO.getSchema(),
                         panel).setEnabled(!attrTO.isReadonly()));
             }
-        };
+        });
+    }
+
+    @Override
+    protected SchemaType getSchemaType() {
+        return SchemaType.VIRTUAL;
+    }
+
+    @Override
+    protected Set<AttrTO> getAttrsFromAnyTO() {
+        return anyTO.getVirAttrs();
+    }
+
+    @Override
+    protected void setAttrs() {
+        List<AttrTO> attrs = new ArrayList<>();
+
+        Map<String, AttrTO> attrMap = anyTO.getVirAttrMap();
+
+        for (VirSchemaTO schema : schemas.values()) {
+            AttrTO attrTO = new AttrTO();
+            attrTO.setSchema(schema.getKey());
+            if (attrMap.containsKey(schema.getKey())) {
+                attrTO.getValues().addAll(attrMap.get(schema.getKey()).getValues());
+            } else {
+                attrTO.getValues().add(StringUtils.EMPTY);
+            }
+
+            attrs.add(attrTO);
+        }
 
-        attributesContainer.add(attributes);
+        anyTO.getVirAttrs().clear();
+        anyTO.getVirAttrs().addAll(attrs);
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/resources/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.html b/client/console/src/main/resources/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.html
new file mode 100644
index 0000000..c969faa
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.html
@@ -0,0 +1,54 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:head>
+    <link rel="stylesheet" type="text/css" href="webjars/codemirror/${codemirror.version}/lib/codemirror.css"/>
+
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/lib/codemirror.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/mode/javascript/javascript.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/display/autorefresh.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/search/search.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/search/searchcursor.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/edit/matchbrackets.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/edit/closebrackets.js"></script>
+    <script type="text/javascript">
+      function updateTextArea(editor) {
+        document.getElementById("consoleLayoutInfoDefForm").children["consoleLayoutInfo"].value = editor.getValue();
+      }
+    </script>
+    <style>
+      .w_content_3 {
+        padding: 0;
+        color: #333333;
+        font-family: Verdana,Tahoma,sans-serif;
+        font-size: 100%;
+        border: 1px solid #BBBBBB;
+        padding: 1%;
+      }
+    </style>
+  </wicket:head>
+  <wicket:panel>
+    <div style="padding: 1%;">
+      <div class="w_content_3" id="consoleLayoutInfoDefForm">
+        <textarea wicket:id="consoleLayoutInfo" id="consoleLayoutInfo" name="consoleLayoutInfo" style="width: 100%; height: 350px;">
+        </textarea>
+      </div>
+    </div>
+  </wicket:panel>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/resources/org/apache/syncope/client/console/notifications/MailTemplateContentModal.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/notifications/MailTemplateContentModal.html b/client/console/src/main/resources/org/apache/syncope/client/console/notifications/MailTemplateContentModal.html
index 8217a07..2f30d1f 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/notifications/MailTemplateContentModal.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/notifications/MailTemplateContentModal.html
@@ -17,39 +17,37 @@ specific language governing permissions and limitations
 under the License.
 -->
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <head><title></title></head>
-  <body>
-    <wicket:head>
-      <link rel="stylesheet" type="text/css" href="webjars/codemirror/${codemirror.version}/lib/codemirror.css"/>
+  <wicket:head>
+    <link rel="stylesheet" type="text/css" href="webjars/codemirror/${codemirror.version}/lib/codemirror.css"/>
 
-      <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/lib/codemirror.js"></script>
-      <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/mode/xml/xml.js"></script>
-      <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/display/autorefresh.js"></script>
-      <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/search/search.js"></script>
-      <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/search/searchcursor.js"></script>
-      <script type="text/javascript">
-        function updateTextArea(editor) {
-          document.getElementById("templateDefForm").children["template"].value = editor.getValue();
-        }
-      </script>
-      <style>
-        .w_content_3 {
-          padding: 0;
-          color: #333333;
-          font-family: Verdana,Tahoma,sans-serif;
-          font-size: 100%;
-          border: 1px solid #BBBBBB;
-          padding: 1%;
-        }
-      </style>
-    </wicket:head>
-    <wicket:panel>
-      <div style="padding: 1%;">
-        <div class="w_content_3" id="templateDefForm">
-          <textarea wicket:id="template" id="template" name="template" style="width: 100%; height: 350px;">
-          </textarea>
-        </div>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/lib/codemirror.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/mode/xml/xml.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/display/autorefresh.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/search/search.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/search/searchcursor.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/edit/closetag.js"></script>
+    <script type="text/javascript">
+      function updateTextArea(editor) {
+        document.getElementById("templateDefForm").children["template"].value = editor.getValue();
+      }
+    </script>
+    <style>
+      .w_content_3 {
+        padding: 0;
+        color: #333333;
+        font-family: Verdana,Tahoma,sans-serif;
+        font-size: 100%;
+        border: 1px solid #BBBBBB;
+        padding: 1%;
+      }
+    </style>
+  </wicket:head>
+  <wicket:panel>
+    <div style="padding: 1%;">
+      <div class="w_content_3" id="templateDefForm">
+        <textarea wicket:id="template" id="template" name="template" style="width: 100%; height: 350px;">
+        </textarea>
       </div>
-    </wicket:panel>
-  </body>
+    </div>
+  </wicket:panel>
 </html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html b/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
index 39ab5ca..6c705a9 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/BasePage.html
@@ -107,7 +107,6 @@ under the License.
                 <li wicket:id="securityquestionsLI"><a href="#" wicket:id="securityquestions"><i class="fa fa-question"></i><wicket:message key="securityQuestions"/></a></li>
                 <li wicket:id="workflowLI"><a href="#" wicket:id="workflow"><i class="fa fa-share-alt"></i><wicket:message key="workflow"/></a></li>
                 <li wicket:id="logsLI"><a href="#" wicket:id="logs"><i class="fa fa-file-text-o"></i><wicket:message key="logs"/></a></li>
-                <li wicket:id="layoutsLI"><a href="#" wicket:id="layouts"><i class="fa fa-object-ungroup"></i><wicket:message key="layouts"/></a></li>
                 <li wicket:id="typesLI"><a href="#" wicket:id="types"><i class="fa fa-wrench"></i><wicket:message key="types"/></a></li>
                 <li wicket:id="notificationsLI"><a href="#" wicket:id="notifications"><i class="fa fa-envelope-o"></i><wicket:message key="notifications"/></a></li>
                 <li wicket:id="parametersLI"><a href="#" wicket:id="parameters"><i class="fa fa-cog"></i><wicket:message key="parameters"/></a></li>

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/resources/org/apache/syncope/client/console/pages/Layouts.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Layouts.html b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Layouts.html
deleted file mode 100644
index a5e0c54..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Layouts.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <wicket:extend>
-
-    <section class="content-header">
-      <h1>
-        &nbsp;
-        <small>Work in progress</small>
-      </h1>
-      <ol class="breadcrumb">
-        <li><a wicket:id="dashboardBr"><i class="fa fa-dashboard"></i> <wicket:message key="dashboard"/></a></li>
-        <li class="active"><wicket:message key="configuration"/></li>
-        <li class="active"><wicket:message key="layouts"/></li>
-      </ol>
-    </section>
-
-    <section class="content">
-      <div class="progress progress active" style="margin:100px">
-        <div style="width: 70%" aria-valuemax="100" aria-valuemin="0" aria-valuenow="20" role="progressbar" class="progress-bar progress-bar-success progress-bar-striped">
-          <span class="sr-only">20% Complete</span>
-        </div>
-      </div>
-    </section>
-
-  </wicket:extend>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/resources/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.html
index 6e979ea..0b51d5e 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.html
@@ -25,6 +25,7 @@ under the License.
     <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/display/autorefresh.js"></script>
     <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/search/search.js"></script>
     <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/search/searchcursor.js"></script>
+    <script type="text/javascript" src="webjars/codemirror/${codemirror.version}/addon/edit/closetag.js"></script>
     <script type="text/javascript">
       function updateTextArea(editor) {
         document.getElementById("workflowDefArea").value = editor.getValue();

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.html
index 28ce9e7..a90a790 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.html
@@ -45,6 +45,7 @@ under the License.
     <span wicket:id="panelEdit">[plus]</span>
     <span wicket:id="panelHtmlEdit">[plus]</span>
     <span wicket:id="panelTextEdit">[plus]</span>
+    <span wicket:id="panelLayoutEdit">[plus]</span>
     <span wicket:id="panelExport">[plus]</span>
     <span wicket:id="panelPropagationTasks">[plus]</span>
     <span wicket:id="panelNotificationTasks">[plus]</span>
@@ -69,7 +70,7 @@ under the License.
     </wicket:fragment>
 
     <wicket:fragment wicket:id="fragmentClaim">
-      <a href="#" wicket:id="claimLink" class="btn"><i id="actionLink" class="fa fa-thumbs-o-up" alt="claim icon" title="Claim"></i></a>
+      <a href="#" wicket:id="claimLink" class="btn"><i id="actionLink" class="fa fa-ticket" alt="claim icon" title="Claim"></i></a>
     </wicket:fragment>
 
     <wicket:fragment wicket:id="fragmentManageResources">
@@ -128,6 +129,10 @@ under the License.
       <a href="#" wicket:id="textEditLink" class="btn"><i id="actionLink" class="fa fa-file-text-o" alt="text edit icon" title="TEXT Edit"></i></a>
     </wicket:fragment>
 
+    <wicket:fragment wicket:id="fragmentLayoutEdit">
+      <a href="#" wicket:id="layoutEditLink" class="btn"><i id="actionLink" class="fa fa-object-ungroup" alt="layout edit icon" title="Layout Edit"></i></a>
+    </wicket:fragment>
+
     <wicket:fragment wicket:id="fragmentReset">
       <a href="#" wicket:id="resetLink" class="btn"><img id="actionLink" src="img/actions/reset.png" alt="reset icon" title="Reset sync token"/></a>
     </wicket:fragment>

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/DerAttrs.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/DerAttrs.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/DerAttrs.html
index defa627..1ec59d5 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/DerAttrs.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/DerAttrs.html
@@ -16,18 +16,15 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org" >
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div id="emptyPlaceholder"/>
-      <div wicket:id="derAttrContainer">
-        <div class="form-group" wicket:id="attrs">
-          <span wicket:id="panel">
-            [panel for dynamic input type markup]
-          </span>
-        </div>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div id="emptyPlaceholder"/>
+    <div wicket:id="schemas">
+      <div class="form-group">
+        <span wicket:id="panel">
+          [panel for dynamic input type markup]
+        </span>
       </div>
-    </wicket:panel>
-  </body>
-</html>
+    </div>
+  </wicket:panel>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/VirAttrs.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/VirAttrs.html b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/VirAttrs.html
index a0d9eb3..1ec59d5 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/VirAttrs.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/wizards/any/VirAttrs.html
@@ -16,18 +16,15 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 -->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org" >
-  <head><title></title></head>
-  <body>
-    <wicket:panel>
-      <div id="emptyPlaceholder"/>
-      <div wicket:id="virAttrContainer">
-        <div class="form-group" wicket:id="attrs">
-          <span wicket:id="panel">
-            [panel for dynamic input type markup]
-          </span>
-        </div>
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:panel>
+    <div id="emptyPlaceholder"/>
+    <div wicket:id="schemas">
+      <div class="form-group">
+        <span wicket:id="panel">
+          [panel for dynamic input type markup]
+        </span>
       </div>
-    </wicket:panel>
-  </body>
-</html>
+    </div>
+  </wicket:panel>
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormTO.java
----------------------------------------------------------------------
diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormTO.java b/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormTO.java
index 97be831..e6027f1 100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormTO.java
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/to/WorkflowFormTO.java
@@ -38,14 +38,12 @@ public class WorkflowFormTO extends AbstractBaseBean {
 
     private static final long serialVersionUID = -7044543391316529128L;
 
-    private String userKey;
+    private String username;
 
     private String taskId;
 
     private String key;
 
-    private String description;
-
     private Date createTime;
 
     private Date dueDate;
@@ -54,12 +52,12 @@ public class WorkflowFormTO extends AbstractBaseBean {
 
     private final List<WorkflowFormPropertyTO> properties = new ArrayList<>();
 
-    public String getUserKey() {
-        return userKey;
+    public String getUsername() {
+        return username;
     }
 
-    public void setUserKey(final String userKey) {
-        this.userKey = userKey;
+    public void setUsername(final String username) {
+        this.username = username;
     }
 
     public String getTaskId() {
@@ -86,14 +84,6 @@ public class WorkflowFormTO extends AbstractBaseBean {
         this.createTime = createTime;
     }
 
-    public String getDescription() {
-        return description;
-    }
-
-    public void setDescription(final String description) {
-        this.description = description;
-    }
-
     public Date getDueDate() {
         return dueDate;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
index 132e27a..782a3d2 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/RoleService.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.common.rest.api.service;
 
+import java.io.InputStream;
 import java.util.List;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
@@ -86,4 +87,35 @@ public interface RoleService extends JAXRSService {
     @DELETE
     @Path("{key}")
     void delete(@NotNull @PathParam("key") String key);
+
+    /**
+     * Gets the console layout information as JSON string for the role with the given key, if available.
+     *
+     * @param key role key
+     * @return console layout information as JSON string for the role with the given key, if available
+     */
+    @GET
+    @Path("{key}/consoleLayout")
+    @Produces({ MediaType.APPLICATION_JSON })
+    Response getConsoleLayoutInfo(@NotNull @PathParam("key") String key);
+
+    /**
+     * Sets the console layout information as JSON string for the role with the given key, if available.
+     *
+     * @param key role key
+     * @param consoleLayoutInfoIn console layout information to be set
+     */
+    @PUT
+    @Path("{key}/consoleLayout")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    void setConsoleLayoutInfo(@NotNull @PathParam("key") String key, InputStream consoleLayoutInfoIn);
+
+    /**
+     * Removes the console layout information for the role with the given key, if available.
+     *
+     * @param key role key
+     */
+    @DELETE
+    @Path("{key}/consoleLayout")
+    void removeConsoleLayoutInfo(@NotNull @PathParam("key") String key);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
index 92cb880..ced5dc7 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/RoleLogic.java
@@ -24,6 +24,7 @@ import java.util.List;
 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.to.RoleTO;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
@@ -99,6 +100,38 @@ public class RoleLogic extends AbstractTransactionalLogic<RoleTO> {
         return deleted;
     }
 
+    @PreAuthorize("isAuthenticated()")
+    public String getConsoleLayoutInfo(final String key) {
+        Role role = roleDAO.find(key);
+        if (role == null) {
+            LOG.error("Could not find role '" + key + "'");
+
+            throw new NotFoundException(key);
+        }
+
+        String consoleLayout = role.getConsoleLayoutInfo();
+        if (StringUtils.isBlank(consoleLayout)) {
+            LOG.error("Could not find console layout for Role '" + key + "'");
+
+            throw new NotFoundException("Console layout for role " + key);
+        }
+
+        return consoleLayout;
+    }
+
+    @PreAuthorize("hasRole('" + StandardEntitlement.ROLE_UPDATE + "')")
+    public void setConsoleLayoutInfo(final String key, final String consoleLayout) {
+        Role role = roleDAO.find(key);
+        if (role == null) {
+            LOG.error("Could not find role '" + key + "'");
+
+            throw new NotFoundException(key);
+        }
+
+        role.setConsoleLayoutInfo(consoleLayout);
+        roleDAO.save(role);
+    }
+
     @Override
     protected RoleTO resolveReference(final Method method, final Object... args)
             throws UnresolvedReferenceException {
@@ -115,7 +148,7 @@ public class RoleLogic extends AbstractTransactionalLogic<RoleTO> {
             }
         }
 
-        if ((key != null) && !key.equals(0L)) {
+        if (key != null) {
             try {
                 return binder.getRoleTO(roleDAO.find(key));
             } catch (Throwable ignore) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
----------------------------------------------------------------------
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
index 60d62f1..441f87a 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/Role.java
@@ -33,4 +33,8 @@ public interface Role extends ProvidedKeyEntity {
     DynRoleMembership getDynMembership();
 
     void setDynMembership(DynRoleMembership dynMembership);
+
+    String getConsoleLayoutInfo();
+
+    void setConsoleLayoutInfo(String consoleLayoutInfo);
 }


[3/4] syncope git commit: [SYNCOPE-790] Now binding JSON configuration to role which allows to selectively enable user / group / anyObject wizard steps, customize plain / derived / virtual attributes appearance order and even providing custom class

Posted by il...@apache.org.
[SYNCOPE-790] Now binding JSON configuration to role which allows to selectively enable user / group / anyObject wizard steps, customize plain / derived / virtual attributes appearance order and even providing custom class


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

Branch: refs/heads/master
Commit: 5b47ab2354a0272ad9c5d3298d8a1fc2565a0c1f
Parents: 8dc9ec5
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Tue Apr 26 17:45:57 2016 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Tue Apr 26 17:46:19 2016 +0200

----------------------------------------------------------------------
 .../console/approvals/ApprovalDetails.java      |  16 +--
 .../approvals/ApprovalDirectoryPanel.java       |   2 +-
 .../client/console/commons/AttrLayoutType.java  |  95 ------------
 .../syncope/client/console/commons/Mode.java    |   1 -
 .../console/layout/AbstractAnyFormLayout.java   | 110 ++++++++++++++
 .../syncope/client/console/layout/AnyForm.java  |  27 ++++
 .../client/console/layout/AnyObjectForm.java    |  25 ++++
 .../console/layout/AnyObjectFormLayoutInfo.java |  43 ++++++
 .../console/layout/ConsoleLayoutInfoModal.java  | 114 +++++++++++++++
 .../console/layout/FormLayoutInfoUtils.java     | 144 +++++++++++++++++++
 .../client/console/layout/GroupForm.java        |  25 ++++
 .../console/layout/GroupFormLayoutInfo.java     |  63 ++++++++
 .../syncope/client/console/layout/UserForm.java |  25 ++++
 .../console/layout/UserFormLayoutInfo.java      |  63 ++++++++
 .../notifications/MailTemplateContentModal.java |  15 +-
 .../MailTemplateDirectoryPanel.java             |  13 +-
 .../syncope/client/console/pages/BasePage.java  |   6 -
 .../syncope/client/console/pages/Layouts.java   |  33 -----
 .../syncope/client/console/panels/AnyPanel.java |  55 ++++---
 .../syncope/client/console/panels/Realm.java    |  12 +-
 .../console/panels/RoleDirectoryPanel.java      |  25 ++++
 .../panels/XMLWorkflowEditorModalPanel.java     |   3 +
 .../console/rest/ConfigurationRestClient.java   |  30 +---
 .../console/rest/NotificationRestClient.java    |   6 +-
 .../client/console/rest/RoleRestClient.java     |  30 +++-
 .../client/console/rest/SchemaRestClient.java   |  17 ---
 .../wicket/markup/html/form/ActionLink.java     |   1 +
 .../markup/html/form/ActionLinksPanel.java      |  20 +++
 .../client/console/widgets/ApprovalsWidget.java |   5 +-
 .../wizards/AbstractModalPanelBuilder.java      |  22 +--
 .../console/wizards/ModalPanelBuilder.java      |  49 +++++++
 .../client/console/wizards/WizardMgtPanel.java  |  16 ++-
 .../console/wizards/any/AbstractAttrs.java      | 116 +++++++++++++--
 .../wizards/any/AnyObjectWizardBuilder.java     |  29 ++--
 .../console/wizards/any/AnyWizardBuilder.java   | 100 +++++++++----
 .../client/console/wizards/any/AuxClasses.java  |   9 +-
 .../client/console/wizards/any/DerAttrs.java    | 105 ++++++--------
 .../client/console/wizards/any/Details.java     |   5 +-
 .../console/wizards/any/GroupDetails.java       |   8 +-
 .../console/wizards/any/GroupWizardBuilder.java |  45 +++---
 .../client/console/wizards/any/PlainAttrs.java  | 134 ++++++-----------
 .../client/console/wizards/any/Roles.java       |   2 +-
 .../client/console/wizards/any/UserDetails.java |  11 +-
 .../wizards/any/UserInformationPanel.java       |  10 +-
 .../console/wizards/any/UserWizardBuilder.java  |  34 +++--
 .../client/console/wizards/any/VirAttrs.java    | 103 ++++++-------
 .../console/layout/ConsoleLayoutInfoModal.html  |  54 +++++++
 .../notifications/MailTemplateContentModal.html |  64 ++++-----
 .../syncope/client/console/pages/BasePage.html  |   1 -
 .../syncope/client/console/pages/Layouts.html   |  43 ------
 .../panels/XMLWorkflowEditorModalPanel.html     |   1 +
 .../markup/html/form/ActionLinksPanel.html      |   7 +-
 .../client/console/wizards/any/DerAttrs.html    |  25 ++--
 .../client/console/wizards/any/VirAttrs.html    |  25 ++--
 .../syncope/common/lib/to/WorkflowFormTO.java   |  20 +--
 .../common/rest/api/service/RoleService.java    |  32 +++++
 .../apache/syncope/core/logic/RoleLogic.java    |  35 ++++-
 .../core/persistence/api/entity/Role.java       |   4 +
 .../core/persistence/jpa/entity/JPARole.java    |  15 ++
 .../main/resources/domains/MasterContent.xml    |  14 --
 .../persistence/jpa/inner/MultitenancyTest.java |   2 +-
 .../persistence/jpa/inner/PlainSchemaTest.java  |   2 +-
 .../test/resources/domains/MasterContent.xml    |  16 +--
 .../src/test/resources/domains/TwoContent.xml   |  14 --
 .../core/rest/cxf/service/RoleServiceImpl.java  |  38 +++++
 .../activiti/ActivitiUserWorkflowAdapter.java   |   4 +-
 .../console/panels/CamelRoutesDetailsPanel.java |   2 +
 .../console/panels/CamelRoutesDetailsPanel.html |   1 +
 .../apache/syncope/fit/console/BaseITCase.java  |   4 -
 .../syncope/fit/core/MultitenancyITCase.java    |   2 +-
 .../syncope/fit/core/UserWorkflowITCase.java    |   4 +-
 71 files changed, 1485 insertions(+), 766 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
index c5787ed..d2d9c41 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
@@ -18,14 +18,12 @@
  */
 package org.apache.syncope.client.console.approvals;
 
-import java.util.List;
+import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
 import org.apache.syncope.client.console.panels.MultilevelPanel;
 import org.apache.syncope.client.console.rest.AnyTypeRestClient;
 import org.apache.syncope.client.console.rest.UserRestClient;
 import org.apache.syncope.client.console.wizards.AjaxWizard;
-import org.apache.syncope.client.console.wizards.any.AnyHandler;
 import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
-import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.wicket.PageReference;
@@ -37,12 +35,10 @@ public class ApprovalDetails extends MultilevelPanel.SecondLevel {
     public ApprovalDetails(final PageReference pageRef, final WorkflowFormTO formTO) {
         super(MultilevelPanel.SECOND_LEVEL_ID);
 
-        final UserTO userTO = new UserRestClient().read(formTO.getUserKey());
-        final List<String> anyTypeClasses = new AnyTypeRestClient().read(AnyTypeKind.USER.name()).getClasses();
-
-        final AjaxWizard<AnyHandler<UserTO>> wizard = new UserWizardBuilder(userTO, anyTypeClasses, pageRef).
-                build(AjaxWizard.Mode.READONLY);
-
-        add(wizard);
+        add(new UserWizardBuilder(new UserRestClient().read(formTO.getUsername()),
+                new AnyTypeRestClient().read(AnyTypeKind.USER.name()).getClasses(),
+                new UserFormLayoutInfo(),
+                pageRef).
+                build(AjaxWizard.Mode.READONLY));
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
index bfe72e0..b176205 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
@@ -79,7 +79,7 @@ public class ApprovalDirectoryPanel
         columns.add(new PropertyColumn<WorkflowFormTO, String>(
                 new ResourceModel("key"), "key", "key"));
         columns.add(new PropertyColumn<WorkflowFormTO, String>(
-                new ResourceModel("description"), "description", "description"));
+                new ResourceModel("username"), "username", "username"));
         columns.add(new DatePropertyColumn<WorkflowFormTO>(
                 new ResourceModel("createTime"), "createTime", "createTime"));
         columns.add(new DatePropertyColumn<WorkflowFormTO>(

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/commons/AttrLayoutType.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/AttrLayoutType.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/AttrLayoutType.java
deleted file mode 100644
index 9aefe4c..0000000
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/AttrLayoutType.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.commons;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-
-public enum AttrLayoutType {
-
-    ADMIN_USER("admin.user.layout", Mode.ADMIN, AnyTypeKind.USER),
-    SELF_USER("self.user.layout", Mode.SELF, AnyTypeKind.USER),
-    ADMIN_GROUP("admin.group.layout", Mode.ADMIN, AnyTypeKind.GROUP),
-    SELF_GROUP("self.group.layout", Mode.SELF, AnyTypeKind.GROUP);
-
-    private final String confKey;
-
-    private final Mode mode;
-
-    private final AnyTypeKind anyTypeKind;
-
-    AttrLayoutType(final String confKey, final Mode mode, final AnyTypeKind anyTypeKind) {
-        this.confKey = confKey;
-        this.mode = mode;
-        this.anyTypeKind = anyTypeKind;
-    }
-
-    public String getConfKey() {
-        return confKey;
-    }
-
-    public Mode getMode() {
-        return mode;
-    }
-
-    public AnyTypeKind getAnyTypeKind() {
-        return anyTypeKind;
-    }
-
-    public static List<String> confKeys() {
-        List<String> confKeys = new ArrayList<>();
-        for (AttrLayoutType value : values()) {
-            confKeys.add(value.getConfKey());
-        }
-
-        return confKeys;
-    }
-
-    public static AttrLayoutType valueOf(final Mode mode, final AnyTypeKind anyTypeKind) {
-        AttrLayoutType result = null;
-        if (mode == Mode.ADMIN) {
-            switch (anyTypeKind) {
-                case USER:
-                    result = ADMIN_USER;
-                    break;
-
-                case GROUP:
-                    result = ADMIN_GROUP;
-                    break;
-
-                default:
-            }
-        } else if (mode == Mode.SELF) {
-            switch (anyTypeKind) {
-                case USER:
-                    result = SELF_USER;
-                    break;
-
-                case GROUP:
-                    result = SELF_GROUP;
-                    break;
-
-                default:
-            }
-        }
-
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/commons/Mode.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/Mode.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/Mode.java
index 27dad64..3d4c956 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/Mode.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/Mode.java
@@ -21,7 +21,6 @@ package org.apache.syncope.client.console.commons;
 public enum Mode {
 
     ADMIN,
-    SELF,
     TEMPLATE;
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/AbstractAnyFormLayout.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/AbstractAnyFormLayout.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/AbstractAnyFormLayout.java
new file mode 100644
index 0000000..91c887a
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/AbstractAnyFormLayout.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.layout;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.common.lib.to.AnyTO;
+
+public abstract class AbstractAnyFormLayout<A extends AnyTO, F extends AnyForm<A>> implements Serializable {
+
+    private static final long serialVersionUID = -6061683026789976508L;
+
+    private Class<F> formClass;
+
+    private boolean auxClasses = true;
+
+    private boolean plainAttrs = true;
+
+    private final List<String> whichPlainAttrs = new ArrayList<>();
+
+    private boolean derAttrs = true;
+
+    private final List<String> whichDerAttrs = new ArrayList<>();
+
+    private boolean virAttrs = true;
+
+    private final List<String> whichVirAttrs = new ArrayList<>();
+
+    private boolean resources = true;
+
+    protected abstract Class<? extends F> getDefaultFormClass();
+
+    public Class<? extends F> getFormClass() {
+        return formClass == null ? getDefaultFormClass() : formClass;
+    }
+
+    public void setFormClass(final Class<F> formClass) {
+        this.formClass = formClass;
+    }
+
+    public boolean isAuxClasses() {
+        return auxClasses;
+    }
+
+    public void setAuxClasses(final boolean auxClasses) {
+        this.auxClasses = auxClasses;
+    }
+
+    public boolean isPlainAttrs() {
+        return plainAttrs;
+    }
+
+    public void setPlainAttrs(final boolean plainAttrs) {
+        this.plainAttrs = plainAttrs;
+    }
+
+    public List<String> getWhichPlainAttrs() {
+        return whichPlainAttrs;
+    }
+
+    public boolean isDerAttrs() {
+        return derAttrs;
+    }
+
+    public void setDerAttrs(final boolean derAttrs) {
+        this.derAttrs = derAttrs;
+    }
+
+    public List<String> getWhichDerAttrs() {
+        return whichDerAttrs;
+    }
+
+    public boolean isVirAttrs() {
+        return virAttrs;
+    }
+
+    public void setVirAttrs(final boolean virAttrs) {
+        this.virAttrs = virAttrs;
+    }
+
+    public List<String> getWhichVirAttrs() {
+        return whichVirAttrs;
+    }
+
+    public boolean isResources() {
+        return resources;
+    }
+
+    public void setResources(final boolean resources) {
+        this.resources = resources;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyForm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyForm.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyForm.java
new file mode 100644
index 0000000..fc02efe
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyForm.java
@@ -0,0 +1,27 @@
+/*
+ * 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.layout;
+
+import org.apache.syncope.client.console.wizards.ModalPanelBuilder;
+import org.apache.syncope.client.console.wizards.any.AnyHandler;
+import org.apache.syncope.common.lib.to.AnyTO;
+
+public interface AnyForm<A extends AnyTO> extends ModalPanelBuilder<AnyHandler<A>> {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectForm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectForm.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectForm.java
new file mode 100644
index 0000000..c8b7c0c
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectForm.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.layout;
+
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+
+public interface AnyObjectForm extends AnyForm<AnyObjectTO> {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectFormLayoutInfo.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectFormLayoutInfo.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectFormLayoutInfo.java
new file mode 100644
index 0000000..211aa25
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectFormLayoutInfo.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.layout;
+
+import org.apache.syncope.client.console.wizards.any.AnyObjectWizardBuilder;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+
+public class AnyObjectFormLayoutInfo extends AbstractAnyFormLayout<AnyObjectTO, AnyObjectForm> {
+
+    private static final long serialVersionUID = -5573691733739618500L;
+
+    private boolean relationships = true;
+
+    @Override
+    protected Class<? extends AnyObjectForm> getDefaultFormClass() {
+        return AnyObjectWizardBuilder.class;
+    }
+
+    public boolean isRelationships() {
+        return relationships;
+    }
+
+    public void setRelationships(final boolean relationships) {
+        this.relationships = relationships;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.java
new file mode 100644
index 0000000..2b48d49
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.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.client.console.layout;
+
+import java.io.Serializable;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.AbstractModalPanel;
+import org.apache.syncope.client.console.rest.AnyTypeRestClient;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnLoadHeaderItem;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.TextArea;
+import org.apache.wicket.model.PropertyModel;
+
+public class ConsoleLayoutInfoModal extends AbstractModalPanel<Serializable> {
+
+    private static final long serialVersionUID = -5110368813584745668L;
+
+    private final ConsoleLayoutInfo consoleLayoutInfo;
+
+    public ConsoleLayoutInfoModal(
+            final BaseModal<Serializable> modal,
+            final ConsoleLayoutInfo consoleLayoutInfo,
+            final PageReference pageRef) {
+
+        super(modal, pageRef);
+        this.consoleLayoutInfo = consoleLayoutInfo;
+
+        TextArea<String> consoleLayoutInfoDefArea =
+                new TextArea<>("consoleLayoutInfo", new PropertyModel<String>(consoleLayoutInfo, "content"));
+        consoleLayoutInfoDefArea.setMarkupId("consoleLayoutInfo").setOutputMarkupPlaceholderTag(true);
+        add(consoleLayoutInfoDefArea);
+    }
+
+    @Override
+    public void renderHead(final IHeaderResponse response) {
+        super.renderHead(response);
+        response.render(OnLoadHeaderItem.forScript(
+                "CodeMirror.fromTextArea(document.getElementById('consoleLayoutInfo'), {"
+                + "  lineNumbers: true, "
+                + "  lineWrapping: true, "
+                + "  matchBrackets: true,"
+                + "  autoCloseBrackets: true,"
+                + "  autoRefresh: true"
+                + "}).on('change', updateTextArea);"));
+    }
+
+    @Override
+    public ConsoleLayoutInfo getItem() {
+        return consoleLayoutInfo;
+    }
+
+    @Override
+    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+        try {
+            new RoleRestClient().setConsoleLayoutInfo(
+                    consoleLayoutInfo.getKey(), consoleLayoutInfo.getContent());
+            info(getString(Constants.OPERATION_SUCCEEDED));
+            modal.show(false);
+            modal.close(target);
+        } catch (Exception e) {
+            LOG.error("While updating onsole layout info for role {}", consoleLayoutInfo.getKey(), e);
+            error(StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
+        }
+        SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
+    }
+
+    public static class ConsoleLayoutInfo implements Serializable {
+
+        private static final long serialVersionUID = 961267717148831831L;
+
+        private final String key;
+
+        private String content;
+
+        public ConsoleLayoutInfo(final String key) {
+            this.key = key;
+        }
+
+        public String getKey() {
+            return key;
+        }
+
+        public String getContent() {
+            return content;
+        }
+
+        public void setContent(final String content) {
+            this.content = FormLayoutInfoUtils.defaultConsoleLayoutInfoIfEmpty(content, new AnyTypeRestClient().list());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/FormLayoutInfoUtils.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/FormLayoutInfoUtils.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/FormLayoutInfoUtils.java
new file mode 100644
index 0000000..a5caccb
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/FormLayoutInfoUtils.java
@@ -0,0 +1,144 @@
+/*
+ * 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.layout;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Triple;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AnyTypeTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.wicket.PageReference;
+
+/**
+ * Utility methods for dealing with form layout information.
+ */
+public final class FormLayoutInfoUtils {
+
+    private static final RoleRestClient ROLE_REST_CLIENT = new RoleRestClient();
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    public static Triple<UserFormLayoutInfo, GroupFormLayoutInfo, Map<String, AnyObjectFormLayoutInfo>> fetch(
+            final List<AnyTypeTO> anyTypeTOs) {
+
+        List<String> ownedRoles = SyncopeConsoleSession.get().getSelfTO().getRoles();
+        try {
+            JsonNode tree = null;
+            for (int i = 0; i < ownedRoles.size() && tree == null; i++) {
+                String consoleLayoutInfo = ROLE_REST_CLIENT.readConsoleLayoutInfo(ownedRoles.get(i));
+                if (StringUtils.isNotBlank(consoleLayoutInfo)) {
+                    tree = MAPPER.readTree(consoleLayoutInfo);
+                }
+            }
+            if (tree == null) {
+                tree = MAPPER.createObjectNode();
+            }
+
+            UserFormLayoutInfo userFormLayoutInfo = tree.has(AnyTypeKind.USER.name())
+                    ? MAPPER.treeToValue(tree.get(AnyTypeKind.USER.name()), UserFormLayoutInfo.class)
+                    : new UserFormLayoutInfo();
+
+            GroupFormLayoutInfo groupFormLayoutInfo = tree.has(AnyTypeKind.USER.name())
+                    ? MAPPER.treeToValue(tree.get(AnyTypeKind.GROUP.name()), GroupFormLayoutInfo.class)
+                    : new GroupFormLayoutInfo();
+
+            Map<String, AnyObjectFormLayoutInfo> anyObjectFormLayoutInfos = new HashMap<>();
+            for (AnyTypeTO anyTypeTO : anyTypeTOs) {
+                if (!anyTypeTO.getKey().equals(AnyTypeKind.USER.name())
+                        && !anyTypeTO.getKey().equals(AnyTypeKind.GROUP.name())) {
+
+                    anyObjectFormLayoutInfos.put(
+                            anyTypeTO.getKey(),
+                            tree.has(anyTypeTO.getKey())
+                            ? MAPPER.treeToValue(tree.get(anyTypeTO.getKey()), AnyObjectFormLayoutInfo.class)
+                            : new AnyObjectFormLayoutInfo());
+                }
+            }
+
+            return Triple.of(userFormLayoutInfo, groupFormLayoutInfo, anyObjectFormLayoutInfos);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("While parsing console layout info for "
+                    + SyncopeConsoleSession.get().getSelfTO().getUsername(), e);
+        }
+    }
+
+    public static String defaultConsoleLayoutInfoIfEmpty(final String content, final List<AnyTypeTO> anyTypeTOs) {
+        String result;
+
+        if (StringUtils.isBlank(content)) {
+            try {
+                ObjectNode tree = MAPPER.createObjectNode();
+
+                tree.set(AnyTypeKind.USER.name(), MAPPER.valueToTree(new UserFormLayoutInfo()));
+                tree.set(AnyTypeKind.GROUP.name(), MAPPER.valueToTree(new GroupFormLayoutInfo()));
+                for (AnyTypeTO anyTypeTO : anyTypeTOs) {
+                    if (!anyTypeTO.getKey().equals(AnyTypeKind.USER.name())
+                            && !anyTypeTO.getKey().equals(AnyTypeKind.GROUP.name())) {
+
+                        tree.set(anyTypeTO.getKey(), MAPPER.valueToTree(new AnyObjectFormLayoutInfo()));
+                    }
+                }
+
+                result = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(tree);
+            } catch (IOException e) {
+                throw new IllegalArgumentException("While generating default console layout info for "
+                        + SyncopeConsoleSession.get().getSelfTO().getUsername(), e);
+            }
+        } else {
+            try {
+                result = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(MAPPER.readTree(content));
+            } catch (IOException e) {
+                result = content;
+            }
+        }
+
+        return result;
+    }
+
+    public static <A extends AnyTO, F extends AnyForm<A>, FL extends AbstractAnyFormLayout<A, F>> F instantiate(
+            final A anyTO,
+            final List<String> anyTypeClasses,
+            final FL anyFormLayout,
+            final PageReference pageRef) {
+
+        try {
+            return anyFormLayout.getFormClass().getConstructor(
+                    anyTO.getClass(),
+                    List.class,
+                    anyFormLayout.getClass(),
+                    pageRef.getClass()).
+                    newInstance(anyTO, anyTypeClasses, anyFormLayout, pageRef);
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Could not instantiate " + anyFormLayout.getFormClass().getName(), e);
+        }
+    }
+
+    private FormLayoutInfoUtils() {
+        // private constructor for static utility class
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupForm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupForm.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupForm.java
new file mode 100644
index 0000000..7b8e27f
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupForm.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.layout;
+
+import org.apache.syncope.common.lib.to.GroupTO;
+
+public interface GroupForm extends AnyForm<GroupTO> {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupFormLayoutInfo.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupFormLayoutInfo.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupFormLayoutInfo.java
new file mode 100644
index 0000000..9296300
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupFormLayoutInfo.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.layout;
+
+import org.apache.syncope.client.console.wizards.any.GroupWizardBuilder;
+import org.apache.syncope.common.lib.to.GroupTO;
+
+public class GroupFormLayoutInfo extends AbstractAnyFormLayout<GroupTO, GroupForm> {
+
+    private static final long serialVersionUID = -5573691733739618500L;
+
+    private boolean ownership = true;
+
+    private boolean dynamicMemberships = true;
+
+    private boolean typeExtension = true;
+
+    @Override
+    protected Class<? extends GroupForm> getDefaultFormClass() {
+        return GroupWizardBuilder.class;
+    }
+
+    public boolean isOwnership() {
+        return ownership;
+    }
+
+    public void setOwnership(final boolean ownership) {
+        this.ownership = ownership;
+    }
+
+    public boolean isDynamicMemberships() {
+        return dynamicMemberships;
+    }
+
+    public void setDynamicMemberships(final boolean dynamicMemberships) {
+        this.dynamicMemberships = dynamicMemberships;
+    }
+
+    public boolean isTypeExtension() {
+        return typeExtension;
+    }
+
+    public void setTypeExtension(final boolean typeExtension) {
+        this.typeExtension = typeExtension;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/UserForm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/UserForm.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/UserForm.java
new file mode 100644
index 0000000..04f5d99
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/UserForm.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.layout;
+
+import org.apache.syncope.common.lib.to.UserTO;
+
+public interface UserForm extends AnyForm<UserTO> {
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java
new file mode 100644
index 0000000..c100143
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.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.layout;
+
+import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
+import org.apache.syncope.common.lib.to.UserTO;
+
+public class UserFormLayoutInfo extends AbstractAnyFormLayout<UserTO, UserForm> {
+
+    private static final long serialVersionUID = -5573691733739618500L;
+
+    private boolean passwordManagement = true;
+
+    private boolean roles = true;
+
+    private boolean relationships = true;
+
+    @Override
+    protected Class<? extends UserForm> getDefaultFormClass() {
+        return UserWizardBuilder.class;
+    }
+
+    public boolean isPasswordManagement() {
+        return passwordManagement;
+    }
+
+    public void setPasswordManagement(final boolean passwordManagement) {
+        this.passwordManagement = passwordManagement;
+    }
+
+    public boolean isRoles() {
+        return roles;
+    }
+
+    public void setRoles(final boolean roles) {
+        this.roles = roles;
+    }
+
+    public boolean isRelationships() {
+        return relationships;
+    }
+
+    public void setRelationships(final boolean relationships) {
+        this.relationships = relationships;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
index 9603446..55804cb 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
@@ -25,7 +25,6 @@ import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.panels.AbstractModalPanel;
 import org.apache.syncope.client.console.rest.NotificationRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.common.lib.AbstractBaseBean;
 import org.apache.syncope.common.lib.types.MailTemplateFormat;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -39,12 +38,13 @@ public class MailTemplateContentModal extends AbstractModalPanel<Serializable> {
 
     private static final long serialVersionUID = 2053048734388383021L;
 
-    private final MailTemplateContentTO content;
+    private final MailTemplateContent content;
 
     public MailTemplateContentModal(
             final BaseModal<Serializable> modal,
-            final MailTemplateContentTO content,
+            final MailTemplateContent content,
             final PageReference pageRef) {
+
         super(modal, pageRef);
         this.content = content;
 
@@ -59,12 +59,15 @@ public class MailTemplateContentModal extends AbstractModalPanel<Serializable> {
         response.render(OnLoadHeaderItem.forScript(
                 "CodeMirror.fromTextArea(document.getElementById('template'), {"
                 + "  lineNumbers: true, "
+                + "  lineWrapping: true, "
+                + "  autoCloseTags: true, "
+                + "  mode: 'text/html', "
                 + "  autoRefresh: true"
                 + "}).on('change', updateTextArea);"));
     }
 
     @Override
-    public MailTemplateContentTO getItem() {
+    public MailTemplateContent getItem() {
         return this.content;
     }
 
@@ -83,7 +86,7 @@ public class MailTemplateContentModal extends AbstractModalPanel<Serializable> {
         SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
     }
 
-    public static class MailTemplateContentTO extends AbstractBaseBean {
+    public static class MailTemplateContent implements Serializable {
 
         private static final long serialVersionUID = -1756961687134322845L;
 
@@ -93,7 +96,7 @@ public class MailTemplateContentModal extends AbstractModalPanel<Serializable> {
 
         private final MailTemplateFormat format;
 
-        public MailTemplateContentTO(final String key, final MailTemplateFormat format) {
+        public MailTemplateContent(final String key, final MailTemplateFormat format) {
             this.key = key;
             this.format = format;
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
index 566d2b8..b6fee1a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
@@ -66,13 +66,12 @@ public class MailTemplateDirectoryPanel
         super(id, pageReference, true);
         disableCheckBoxes();
 
-        addOuterObject(utilityModal);
-        setWindowClosedReloadCallback(utilityModal);
-
         modal.size(Modal.Size.Small);
         modal.addSumbitButton();
         setFooterVisibility(true);
 
+        addOuterObject(utilityModal);
+        setWindowClosedReloadCallback(utilityModal);
         utilityModal.size(Modal.Size.Large);
         utilityModal.addSumbitButton();
 
@@ -114,8 +113,8 @@ public class MailTemplateDirectoryPanel
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final MailTemplateTO ignore) {
-                        MailTemplateContentModal.MailTemplateContentTO content =
-                                new MailTemplateContentModal.MailTemplateContentTO(
+                        MailTemplateContentModal.MailTemplateContent content =
+                                new MailTemplateContentModal.MailTemplateContent(
                                         model.getObject().getKey(), MailTemplateFormat.HTML);
                         content.setContent(
                                 restClient.readTemplateFormat(model.getObject().getKey(), MailTemplateFormat.HTML));
@@ -133,8 +132,8 @@ public class MailTemplateDirectoryPanel
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final MailTemplateTO ignore) {
-                        MailTemplateContentModal.MailTemplateContentTO content =
-                                new MailTemplateContentModal.MailTemplateContentTO(
+                        MailTemplateContentModal.MailTemplateContent content =
+                                new MailTemplateContentModal.MailTemplateContent(
                                         model.getObject().getKey(), MailTemplateFormat.TEXT);
                         content.setContent(
                                 restClient.readTemplateFormat(model.getObject().getKey(), MailTemplateFormat.TEXT));

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
index d504cef..b0425a9 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
@@ -188,12 +188,6 @@ public class BasePage extends WebPage implements IAjaxIndicatorAware {
         MetaDataRoleAuthorizationStrategy.authorize(link, WebPage.ENABLE, StandardEntitlement.POLICY_LIST);
         liContainer.add(link);
 
-        liContainer = new WebMarkupContainer(getLIContainerId("layouts"));
-        confULContainer.add(liContainer);
-        link = BookmarkablePageLinkBuilder.build("layouts", Layouts.class);
-        MetaDataRoleAuthorizationStrategy.authorize(link, WebPage.ENABLE, StandardEntitlement.CONFIGURATION_LIST);
-        liContainer.add(link);
-
         liContainer = new WebMarkupContainer(getLIContainerId("notifications"));
         confULContainer.add(liContainer);
         link = BookmarkablePageLinkBuilder.build("notifications", Notifications.class);

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/pages/Layouts.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/Layouts.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/Layouts.java
deleted file mode 100644
index 24464da..0000000
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/Layouts.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.pages;
-
-import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
-import org.apache.wicket.request.mapper.parameter.PageParameters;
-
-public class Layouts extends BasePage {
-
-    private static final long serialVersionUID = -1100228004207271271L;
-
-    public Layouts(final PageParameters parameters) {
-        super(parameters);
-
-        body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
index f6aeaa5..9a3d8c6 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
@@ -18,7 +18,16 @@
  */
 package org.apache.syncope.client.console.panels;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.commons.lang3.tuple.Triple;
+import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
+import org.apache.syncope.client.console.layout.FormLayoutInfoUtils;
+import org.apache.syncope.client.console.layout.GroupFormLayoutInfo;
+import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
 import org.apache.syncope.client.console.panels.search.AbstractSearchPanel;
+import org.apache.syncope.client.console.panels.search.AnyObjectSearchPanel;
 import org.apache.syncope.client.console.panels.search.GroupSearchPanel;
 import org.apache.syncope.client.console.panels.search.SearchClause;
 import org.apache.syncope.client.console.panels.search.SearchClausePanel;
@@ -26,9 +35,6 @@ import org.apache.syncope.client.console.panels.search.SearchUtils;
 import org.apache.syncope.client.console.panels.search.UserSearchPanel;
 import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.tabs.Accordion;
-import org.apache.syncope.client.console.wizards.any.AnyObjectWizardBuilder;
-import org.apache.syncope.client.console.wizards.any.GroupWizardBuilder;
-import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTypeTO;
@@ -54,9 +60,6 @@ import org.apache.wicket.model.StringResourceModel;
 import org.apache.wicket.model.util.ListModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
-import java.util.Collections;
-import org.apache.syncope.client.console.panels.search.AnyObjectSearchPanel;
 
 public class AnyPanel extends Panel {
 
@@ -70,6 +73,8 @@ public class AnyPanel extends Panel {
 
     private final AnyTypeClassRestClient anyTypeClassRestClient = new AnyTypeClassRestClient();
 
+    private final Triple<UserFormLayoutInfo, GroupFormLayoutInfo, Map<String, AnyObjectFormLayoutInfo>> formLayoutInfo;
+
     private final PageReference pageRef;
 
     private AbstractSearchPanel searchPanel;
@@ -78,10 +83,16 @@ public class AnyPanel extends Panel {
 
     @SuppressWarnings({ "unchecked", "unchecked" })
     public AnyPanel(
-            final String id, final AnyTypeTO anyTypeTO, final RealmTO realmTO, final PageReference pageRef) {
+            final String id,
+            final AnyTypeTO anyTypeTO,
+            final RealmTO realmTO,
+            final Triple<UserFormLayoutInfo, GroupFormLayoutInfo, Map<String, AnyObjectFormLayoutInfo>> formLayoutInfo,
+            final PageReference pageRef) {
+
         super(id);
         this.anyTypeTO = anyTypeTO;
         this.realmTO = realmTO;
+        this.formLayoutInfo = formLayoutInfo;
         this.pageRef = pageRef;
 
         // ------------------------
@@ -191,31 +202,39 @@ public class AnyPanel extends Panel {
         final String fiql;
         switch (anyTypeTO.getKind()) {
             case USER:
-                fiql = SyncopeClient.getUserSearchConditionBuilder().is("key").greaterThan(0).query();
+                fiql = SyncopeClient.getUserSearchConditionBuilder().is("key").notNullValue().query();
                 final UserTO userTO = new UserTO();
                 userTO.setRealm(realmTO.getFullPath());
                 panel = new UserDirectoryPanel.Builder(
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
                         anyTypeTO.getKey(),
                         pageRef).setRealm(realmTO.getFullPath()).setFiltered(true).
-                        setFiql(fiql).addNewItemPanelBuilder(new UserWizardBuilder(
-                        userTO, anyTypeTO.getClasses(), pageRef)).build(id);
+                        setFiql(fiql).addNewItemPanelBuilder(FormLayoutInfoUtils.instantiate(
+                        userTO,
+                        anyTypeTO.getClasses(),
+                        formLayoutInfo.getLeft(),
+                        pageRef)).build(id);
                 MetaDataRoleAuthorizationStrategy.authorize(panel, WebPage.RENDER, StandardEntitlement.USER_LIST);
                 break;
+
             case GROUP:
-                fiql = SyncopeClient.getGroupSearchConditionBuilder().is("key").greaterThan(0).query();
+                fiql = SyncopeClient.getGroupSearchConditionBuilder().is("key").notNullValue().query();
                 final GroupTO groupTO = new GroupTO();
                 groupTO.setRealm(realmTO.getFullPath());
                 panel = new GroupDirectoryPanel.Builder(
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
                         anyTypeTO.getKey(),
                         pageRef).setRealm(realmTO.getFullPath()).setFiltered(true).
-                        setFiql(fiql).addNewItemPanelBuilder(new GroupWizardBuilder(
-                        groupTO, anyTypeTO.getClasses(), pageRef)).build(id);
+                        setFiql(fiql).addNewItemPanelBuilder(FormLayoutInfoUtils.instantiate(
+                        groupTO,
+                        anyTypeTO.getClasses(),
+                        formLayoutInfo.getMiddle(),
+                        pageRef)).build(id);
                 // list of group is available to all authenticated users
                 break;
+
             case ANY_OBJECT:
-                fiql = SyncopeClient.getAnyObjectSearchConditionBuilder(anyTypeTO.getKey()).is("key").greaterThan(0).
+                fiql = SyncopeClient.getAnyObjectSearchConditionBuilder(anyTypeTO.getKey()).is("key").notNullValue().
                         query();
                 final AnyObjectTO anyObjectTO = new AnyObjectTO();
                 anyObjectTO.setRealm(realmTO.getFullPath());
@@ -224,11 +243,15 @@ public class AnyPanel extends Panel {
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
                         anyTypeTO.getKey(),
                         pageRef).setRealm(realmTO.getFullPath()).setFiltered(true).
-                        setFiql(fiql).addNewItemPanelBuilder(new AnyObjectWizardBuilder(
-                        anyObjectTO, anyTypeTO.getClasses(), pageRef)).build(id);
+                        setFiql(fiql).addNewItemPanelBuilder(FormLayoutInfoUtils.instantiate(
+                        anyObjectTO,
+                        anyTypeTO.getClasses(),
+                        formLayoutInfo.getRight().get(anyTypeTO.getKey()),
+                        pageRef)).build(id);
                 MetaDataRoleAuthorizationStrategy.authorize(
                         panel, WebPage.RENDER, AnyEntitlement.LIST.getFor(anyTypeTO.getKey()));
                 break;
+
             default:
                 panel = new LabelPanel(id, null);
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/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 41d38ed..9ffb476 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
@@ -23,7 +23,13 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import org.apache.commons.collections4.ComparatorUtils;
+import org.apache.commons.lang3.tuple.Triple;
+import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
+import org.apache.syncope.client.console.layout.FormLayoutInfoUtils;
+import org.apache.syncope.client.console.layout.GroupFormLayoutInfo;
+import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
 import org.apache.syncope.client.console.rest.AnyTypeRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
@@ -52,7 +58,6 @@ public abstract class Realm extends Panel {
 
     private final AnyTypeRestClient anyTypeRestClient = new AnyTypeRestClient();
 
-    @SuppressWarnings({ "unchecked", "unchecked" })
     public Realm(final String id, final RealmTO realmTO, final PageReference pageRef) {
         super(id);
         this.realmTO = realmTO;
@@ -112,6 +117,9 @@ public abstract class Realm extends Panel {
             }
         });
 
+        final Triple<UserFormLayoutInfo, GroupFormLayoutInfo, Map<String, AnyObjectFormLayoutInfo>> formLayoutInfo =
+                FormLayoutInfoUtils.fetch(anyTypeTOs);
+
         Collections.sort(anyTypeTOs, new AnyTypeComparator());
         for (final AnyTypeTO anyTypeTO : anyTypeTOs) {
             tabs.add(new AbstractTab(new Model<>(anyTypeTO.getKey())) {
@@ -120,7 +128,7 @@ public abstract class Realm extends Panel {
 
                 @Override
                 public Panel getPanel(final String panelId) {
-                    return new AnyPanel(panelId, anyTypeTO, realmTO, pageRef);
+                    return new AnyPanel(panelId, anyTypeTO, realmTO, formLayoutInfo, pageRef);
                 }
             });
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
index 755ed04..ba2d44b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
@@ -18,7 +18,9 @@
  */
 package org.apache.syncope.client.console.panels;
 
+import org.apache.syncope.client.console.layout.ConsoleLayoutInfoModal;
 import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
@@ -29,6 +31,7 @@ import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.RoleDataProvider;
 import org.apache.syncope.client.console.rest.RoleRestClient;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
+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.ActionLink.ActionType;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
@@ -51,6 +54,8 @@ public class RoleDirectoryPanel extends DirectoryPanel<RoleTO, RoleHandler, Role
 
     private static final long serialVersionUID = -1100228004207271270L;
 
+    protected final BaseModal<Serializable> utilityModal = new BaseModal<>("outer");
+
     protected RoleDirectoryPanel(final String id, final Builder builder) {
         super(id, builder);
         setShowResultPage(true);
@@ -58,6 +63,11 @@ public class RoleDirectoryPanel extends DirectoryPanel<RoleTO, RoleHandler, Role
         modal.size(Modal.Size.Large);
         initResultTable();
 
+        addOuterObject(utilityModal);
+        setWindowClosedReloadCallback(utilityModal);
+        utilityModal.size(Modal.Size.Large);
+        utilityModal.addSumbitButton();
+
         MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, ENABLE, StandardEntitlement.ROLE_CREATE);
     }
 
@@ -118,6 +128,21 @@ public class RoleDirectoryPanel extends DirectoryPanel<RoleTO, RoleHandler, Role
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final RoleTO ignore) {
+                        ConsoleLayoutInfoModal.ConsoleLayoutInfo info =
+                                new ConsoleLayoutInfoModal.ConsoleLayoutInfo(model.getObject().getKey());
+                        info.setContent(restClient.readConsoleLayoutInfo(model.getObject().getKey()));
+
+                        utilityModal.header(new ResourceModel("console.layout.info", "JSON Content"));
+                        utilityModal.setContent(new ConsoleLayoutInfoModal(utilityModal, info, pageRef));
+                        utilityModal.show(true);
+                        target.add(utilityModal);
+                    }
+                }, ActionLink.ActionType.LAYOUT_EDIT, StandardEntitlement.ROLE_UPDATE).add(new ActionLink<RoleTO>() {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final RoleTO ignore) {
                         try {
                             restClient.delete(model.getObject().getKey());
                             info(getString(Constants.OPERATION_SUCCEEDED));

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.java
index 5c4138d..fa73ec7 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.java
@@ -89,6 +89,9 @@ public class XMLWorkflowEditorModalPanel extends AbstractModalPanel<String> {
         response.render(OnLoadHeaderItem.forScript(
                 "CodeMirror.fromTextArea(document.getElementById('workflowDefArea'), {"
                 + "  lineNumbers: true, "
+                + "  lineWrapping: true, "
+                + "  autoCloseTags: true, "
+                + "  mode: 'text/html', "
                 + "  autoRefresh: true"
                 + "}).on('change', updateTextArea);"));
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
index dfdd842..f8e4863 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
@@ -20,7 +20,6 @@ package org.apache.syncope.client.console.rest;
 
 import java.util.List;
 import javax.ws.rs.core.Response;
-import org.apache.syncope.client.console.commons.AttrLayoutType;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.rest.api.service.ConfigurationService;
@@ -32,17 +31,7 @@ public class ConfigurationRestClient extends BaseRestClient {
     private final SchemaRestClient schemaRestClient = new SchemaRestClient();
 
     public List<AttrTO> list() {
-        final List<AttrTO> attrTOs = getService(ConfigurationService.class).list();
-
-        for (AttrTO attrTO : attrTOs) {
-            for (AttrLayoutType type : AttrLayoutType.values()) {
-                if (type.getConfKey().equals(attrTO.getSchema())) {
-                    attrTOs.remove(attrTO);
-                }
-            }
-        }
-
-        return attrTOs;
+        return getService(ConfigurationService.class).list();
     }
 
     public AttrTO get(final String key) {
@@ -54,23 +43,6 @@ public class ConfigurationRestClient extends BaseRestClient {
         return null;
     }
 
-    public AttrTO readAttrLayout(final AttrLayoutType type) {
-        if (type == null) {
-            return null;
-        }
-
-        AttrTO attrLayout = get(type.getConfKey());
-        if (attrLayout == null) {
-            attrLayout = new AttrTO();
-            attrLayout.setSchema(type.getConfKey());
-        }
-        if (attrLayout.getValues().isEmpty()) {
-            attrLayout.getValues().addAll(schemaRestClient.getPlainSchemaNames());
-        }
-
-        return attrLayout;
-    }
-
     public void set(final AttrTO attrTO) {
         getService(ConfigurationService.class).set(attrTO);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/rest/NotificationRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/NotificationRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/NotificationRestClient.java
index ebf581e..eb7d160 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/NotificationRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/NotificationRestClient.java
@@ -75,13 +75,13 @@ public class NotificationRestClient extends BaseRestClient {
                     getService(MailTemplateService.class).getFormat(key, format).getEntity()),
                     SyncopeConstants.DEFAULT_CHARSET);
         } catch (Exception e) {
-            LOG.info("Error retrieving mail tenplate content");
+            LOG.error("Error retrieving mail template {} as {}", key, format, e);
             return StringUtils.EMPTY;
         }
     }
 
-    public void updateTemplateFormat(final String key, final String str, final MailTemplateFormat format) {
+    public void updateTemplateFormat(final String key, final String content, final MailTemplateFormat format) {
         getService(MailTemplateService.class).setFormat(
-                key, format, IOUtils.toInputStream(str, SyncopeConstants.DEFAULT_CHARSET));
+                key, format, IOUtils.toInputStream(content, SyncopeConstants.DEFAULT_CHARSET));
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
index 116c959..c5a93fb 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
@@ -18,9 +18,13 @@
  */
 package org.apache.syncope.client.console.rest;
 
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.RoleTO;
 import org.apache.syncope.common.rest.api.service.RoleService;
 
@@ -29,7 +33,7 @@ import org.apache.syncope.common.rest.api.service.RoleService;
  */
 public class RoleRestClient extends BaseRestClient {
 
-    private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = -3161863874876938094L;
 
     public void delete(final String key) {
         getService(RoleService.class).delete(key);
@@ -47,10 +51,6 @@ public class RoleRestClient extends BaseRestClient {
         getService(RoleService.class).create(roleTO);
     }
 
-    public List<RoleTO> getAll() {
-        return getService(RoleService.class).list();
-    }
-
     public List<RoleTO> list() {
         return getService(RoleService.class).list();
     }
@@ -59,6 +59,26 @@ public class RoleRestClient extends BaseRestClient {
         return getService(RoleService.class).list().size();
     }
 
+    public String readConsoleLayoutInfo(final String roleKey) {
+        try {
+            return IOUtils.toString(InputStream.class.cast(
+                    getService(RoleService.class).getConsoleLayoutInfo(roleKey).getEntity()),
+                    SyncopeConstants.DEFAULT_CHARSET);
+        } catch (Exception e) {
+            LOG.error("Error retrieving console layout info for role {}", roleKey, e);
+            return StringUtils.EMPTY;
+        }
+    }
+
+    public void setConsoleLayoutInfo(final String roleKey, final String content) {
+        getService(RoleService.class).setConsoleLayoutInfo(
+                roleKey, IOUtils.toInputStream(content, SyncopeConstants.DEFAULT_CHARSET));
+    }
+
+    public void removeConsoleLayoutInfo(final String roleKey) {
+        getService(RoleService.class).removeConsoleLayoutInfo(roleKey);
+    }
+
     public List<String> getAllAvailableEntitlements() {
         List<String> entitlements = new ArrayList<>(getSyncopeService().platform().getEntitlements());
         Collections.sort(entitlements);

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
index d6d5081..b7b1b45 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
@@ -19,9 +19,7 @@
 package org.apache.syncope.client.console.rest;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
-import java.util.ListIterator;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.EntityTOUtils;
@@ -40,21 +38,6 @@ public class SchemaRestClient extends BaseRestClient {
 
     private static final long serialVersionUID = -2479730152700312373L;
 
-    public void filter(
-            final List<? extends AbstractSchemaTO> schemaTOs, final Collection<String> allowed, final boolean exclude) {
-
-        for (ListIterator<? extends AbstractSchemaTO> itor = schemaTOs.listIterator(); itor.hasNext();) {
-            AbstractSchemaTO schema = itor.next();
-            if (exclude) {
-                if (!allowed.contains(schema.getKey())) {
-                    itor.remove();
-                }
-            } else if (allowed.contains(schema.getKey())) {
-                itor.remove();
-            }
-        }
-    }
-
     public <T extends AbstractSchemaTO> List<T> getSchemas(final SchemaType schemaType, final String... kind) {
         List<T> schemas = new ArrayList<>();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
index dc4d596..3d2007d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
@@ -48,6 +48,7 @@ public abstract class ActionLink<T extends Serializable> implements Serializable
         EDIT("read"),
         HTML_EDIT("read"),
         TEXT_EDIT("read"),
+        LAYOUT_EDIT("read"),
         RESET("update"),
         ENABLE("update"),
         NOT_FOND("read"),

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
index 075fc6d..3d6e4ee 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
@@ -63,6 +63,7 @@ public final class ActionLinksPanel<T extends Serializable> extends Panel {
         super.add(new Fragment("panelEdit", "emptyFragment", this));
         super.add(new Fragment("panelHtmlEdit", "emptyFragment", this));
         super.add(new Fragment("panelTextEdit", "emptyFragment", this));
+        super.add(new Fragment("panelLayoutEdit", "emptyFragment", this));
         super.add(new Fragment("panelReset", "emptyFragment", this));
         super.add(new Fragment("panelEnable", "emptyFragment", this));
         super.add(new Fragment("panelNotFound", "emptyFragment", this));
@@ -347,6 +348,25 @@ public final class ActionLinksPanel<T extends Serializable> extends Panel {
                 }.setVisible(link.isEnabled(model.getObject())));
                 break;
 
+            case LAYOUT_EDIT:
+                fragment = new Fragment("panelLayoutEdit", "fragmentLayoutEdit", this);
+
+                fragment.addOrReplace(new IndicatingAjaxLink<Void>("layoutEditLink") {
+
+                    private static final long serialVersionUID = -1876519166660008562L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        link.onClick(target, model.getObject());
+                    }
+
+                    @Override
+                    public String getAjaxIndicatorMarkupId() {
+                        return disableIndicator ? StringUtils.EMPTY : super.getAjaxIndicatorMarkupId();
+                    }
+                }.setVisible(link.isEnabled(model.getObject())));
+                break;
+
             case ENABLE:
                 fragment = new Fragment("panelEnable", "fragmentEnable", this);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java b/client/console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
index 3e704c3..7a50226 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
@@ -22,7 +22,6 @@ import java.io.Serializable;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.pages.Approvals;
@@ -142,9 +141,7 @@ public class ApprovalsWidget extends Panel {
                     @Override
                     protected void onComponentTag(final ComponentTag tag) {
                         super.onComponentTag(tag);
-                        if (StringUtils.isNotBlank(modelObject.getDescription())) {
-                            tag.put("title", modelObject.getDescription().trim());
-                        }
+                        tag.put("title", modelObject.getUsername());
                     }
                 };
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractModalPanelBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractModalPanelBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractModalPanelBuilder.java
index 7209f26..7356e1e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractModalPanelBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractModalPanelBuilder.java
@@ -20,10 +20,9 @@ package org.apache.syncope.client.console.wizards;
 
 import java.io.Serializable;
 import org.apache.commons.lang3.SerializationUtils;
-import org.apache.syncope.client.console.panels.ModalPanel;
 import org.apache.wicket.PageReference;
 
-public abstract class AbstractModalPanelBuilder<T extends Serializable> implements Serializable {
+public abstract class AbstractModalPanelBuilder<T extends Serializable> implements ModalPanelBuilder<T> {
 
     private static final long serialVersionUID = 5241745929825564456L;
 
@@ -44,16 +43,6 @@ public abstract class AbstractModalPanelBuilder<T extends Serializable> implemen
         this.pageRef = pageRef;
     }
 
-    /**
-     * Build the wizard.
-     *
-     * @param id component id.
-     * @param index step index.
-     * @param mode mode.
-     * @return wizard.
-     */
-    public abstract ModalPanel<T> build(final String id, final int index, final AjaxWizard.Mode mode);
-
     protected void onCancelInternal(final T modelObject) {
     }
 
@@ -66,6 +55,7 @@ public abstract class AbstractModalPanelBuilder<T extends Serializable> implemen
         return item;
     }
 
+    @Override
     public T getDefaultItem() {
         return defaultItem;
     }
@@ -80,17 +70,13 @@ public abstract class AbstractModalPanelBuilder<T extends Serializable> implemen
         return SerializationUtils.clone(item);
     }
 
-    /**
-     * Replaces the default value provided with the constructor and nullify working item object.
-     *
-     * @param item new value.
-     * @return the current wizard factory instance.
-     */
+    @Override
     public AbstractModalPanelBuilder<T> setItem(final T item) {
         this.item = item;
         return this;
     }
 
+    @Override
     public PageReference getPageReference() {
         return pageRef;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/ModalPanelBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/ModalPanelBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/ModalPanelBuilder.java
new file mode 100644
index 0000000..62db09a
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/ModalPanelBuilder.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wizards;
+
+import java.io.Serializable;
+import org.apache.syncope.client.console.panels.ModalPanel;
+import org.apache.wicket.PageReference;
+
+public interface ModalPanelBuilder<T extends Serializable> extends Serializable {
+
+    /**
+     * Build the wizard.
+     *
+     * @param id component id.
+     * @param index step index.
+     * @param mode mode.
+     * @return wizard.
+     */
+    ModalPanel<T> build(String id, int index, AjaxWizard.Mode mode);
+
+    T getDefaultItem();
+
+    PageReference getPageReference();
+
+    /**
+     * Replaces the default value provided with the constructor and nullify working item object.
+     *
+     * @param item new value.
+     * @return the current wizard factory instance.
+     */
+    ModalPanelBuilder<T> setItem(T item);
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
index 2a61de7..144e2f4 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
@@ -67,7 +67,7 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
 
     protected final AjaxLink<?> addAjaxLink;
 
-    protected AbstractModalPanelBuilder<T> newItemPanelBuilder;
+    protected ModalPanelBuilder<T> newItemPanelBuilder;
 
     protected NotificationPanel notificationPanel;
 
@@ -252,18 +252,19 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
         return this;
     }
 
-    public <B extends AbstractModalPanelBuilder<T>> WizardMgtPanel<T> setPageRef(final PageReference pageRef) {
+    public <B extends ModalPanelBuilder<T>> WizardMgtPanel<T> setPageRef(final PageReference pageRef) {
         this.pageRef = pageRef;
         return this;
     }
 
-    public <B extends AbstractModalPanelBuilder<T>> WizardMgtPanel<T> setShowResultPage(final boolean showResultPage) {
+    public <B extends ModalPanelBuilder<T>> WizardMgtPanel<T> setShowResultPage(final boolean showResultPage) {
         this.showResultPage = showResultPage;
         return this;
     }
 
-    protected <B extends AbstractModalPanelBuilder<T>> WizardMgtPanel<T> addNewItemPanelBuilder(
+    protected <B extends ModalPanelBuilder<T>> WizardMgtPanel<T> addNewItemPanelBuilder(
             final B panelBuilder, final boolean newItemDefaultButtonEnabled) {
+
         this.newItemPanelBuilder = panelBuilder;
 
         if (this.newItemPanelBuilder != null) {
@@ -321,7 +322,7 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
 
         protected final PageReference pageRef;
 
-        private AbstractModalPanelBuilder<T> newItemPanelBuilder;
+        private ModalPanelBuilder<T> newItemPanelBuilder;
 
         private boolean newItemDefaultButtonEnabled = true;
 
@@ -353,7 +354,7 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
             this.showResultPage = showResultPage;
         }
 
-        public Builder<T> addNewItemPanelBuilder(final AbstractModalPanelBuilder<T> panelBuilder) {
+        public Builder<T> addNewItemPanelBuilder(final ModalPanelBuilder<T> panelBuilder) {
             this.newItemPanelBuilder = panelBuilder;
             return this;
         }
@@ -366,7 +367,8 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
          * @return the current builder.
          */
         public Builder<T> addNewItemPanelBuilder(
-                final AbstractModalPanelBuilder<T> panelBuilder, final boolean newItemDefaultButtonEnabled) {
+                final ModalPanelBuilder<T> panelBuilder, final boolean newItemDefaultButtonEnabled) {
+
             this.newItemDefaultButtonEnabled = newItemDefaultButtonEnabled;
             return addNewItemPanelBuilder(panelBuilder);
         }