You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2015/02/16 09:07:01 UTC

[36/59] [abbrv] [partial] syncope git commit: [SYNCOPE-620] Re-organization completed

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java
new file mode 100644
index 0000000..aa3c3eb
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java
@@ -0,0 +1,468 @@
+/*
+ * 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.panels;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.SelectedEventsPanel.EventSelectionChanged;
+import org.apache.syncope.client.console.panels.SelectedEventsPanel.InspectSelectedEvent;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.to.EventCategoryTO;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.lib.types.AuditElements.EventCategoryType;
+import org.apache.syncope.common.lib.types.AuditLoggerName;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class LoggerCategoryPanel extends Panel {
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(LoggerCategoryPanel.class);
+
+    private static final long serialVersionUID = 6429053774964787734L;
+
+    private final List<EventCategoryTO> eventCategoryTOs;
+
+    private final EventCategoryTO eventCategoryTO = new EventCategoryTO();
+
+    private final WebMarkupContainer categoryContainer;
+
+    private final WebMarkupContainer eventsContainer;
+
+    private final SelectedEventsPanel selectedEventsPanel;
+
+    private final AjaxDropDownChoicePanel<EventCategoryType> type;
+
+    private final AjaxDropDownChoicePanel<String> category;
+
+    private final AjaxDropDownChoicePanel<String> subcategory;
+
+    private final AjaxTextFieldPanel custom;
+
+    private final ActionLinksPanel actionPanel;
+
+    private final IModel<List<String>> model;
+
+    public LoggerCategoryPanel(
+            final String id,
+            final List<EventCategoryTO> eventCategoryTOs,
+            final IModel<List<String>> model,
+            final PageReference pageReference,
+            final String pageId) {
+        super(id);
+
+        this.model = model;
+        selectedEventsPanel = new SelectedEventsPanel("selectedEventsPanel", model);
+        add(selectedEventsPanel);
+
+        this.eventCategoryTOs = eventCategoryTOs;
+
+        categoryContainer = new WebMarkupContainer("categoryContainer");
+        categoryContainer.setOutputMarkupId(true);
+        add(categoryContainer);
+
+        eventsContainer = new WebMarkupContainer("eventsContainer");
+        eventsContainer.setOutputMarkupId(true);
+        add(eventsContainer);
+
+        authorizeList();
+        authorizeChanges();
+
+        categoryContainer.add(new Label("typeLabel", new ResourceModel("type", "type")));
+
+        type = new AjaxDropDownChoicePanel<EventCategoryType>(
+                "type",
+                "type",
+                new PropertyModel<EventCategoryType>(eventCategoryTO, "type"),
+                false);
+        type.setChoices(Arrays.asList(EventCategoryType.values()));
+        type.setStyleSheet("ui-widget-content ui-corner-all");
+        type.setChoiceRenderer(new IChoiceRenderer<EventCategoryType>() {
+
+            private static final long serialVersionUID = 2317134950949778735L;
+
+            @Override
+            public String getDisplayValue(final EventCategoryType eventCategoryType) {
+                return eventCategoryType.name();
+            }
+
+            @Override
+            public String getIdValue(final EventCategoryType eventCategoryType, final int i) {
+                return eventCategoryType.name();
+            }
+        });
+        categoryContainer.add(type);
+
+        type.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                send(LoggerCategoryPanel.this, Broadcast.EXACT, new ChangeCategoryEvent(target, type));
+            }
+        });
+
+        categoryContainer.add(new Label("categoryLabel", new ResourceModel("category", "category")));
+
+        category = new AjaxDropDownChoicePanel<String>(
+                "category",
+                "category",
+                new PropertyModel<String>(eventCategoryTO, "category"),
+                false);
+        category.setChoices(filter(eventCategoryTOs, type.getModelObject()));
+        category.setStyleSheet("ui-widget-content ui-corner-all");
+        categoryContainer.add(category);
+
+        category.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306811L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                send(LoggerCategoryPanel.this, Broadcast.EXACT, new ChangeCategoryEvent(target, category));
+            }
+        });
+
+        categoryContainer.add(new Label("subcategoryLabel", new ResourceModel("subcategory", "subcategory")));
+
+        subcategory = new AjaxDropDownChoicePanel<String>(
+                "subcategory",
+                "subcategory",
+                new PropertyModel<String>(eventCategoryTO, "subcategory"),
+                false);
+        subcategory.setChoices(filter(eventCategoryTOs, type.getModelObject(), category.getModelObject()));
+        subcategory.setStyleSheet("ui-widget-content ui-corner-all");
+        categoryContainer.add(subcategory);
+
+        subcategory.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306812L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                send(LoggerCategoryPanel.this, Broadcast.EXACT, new ChangeCategoryEvent(target, subcategory));
+            }
+        });
+
+        categoryContainer.add(new Label("customLabel", new ResourceModel("custom", "custom")).setVisible(false));
+
+        custom = new AjaxTextFieldPanel("custom", "custom", new Model<String>(null));
+        custom.setStyleSheet("ui-widget-content ui-corner-all short_fixedsize");
+        custom.setVisible(false);
+        custom.setEnabled(false);
+
+        categoryContainer.add(custom);
+
+        actionPanel = new ActionLinksPanel("customActions", new Model(), pageReference);
+        categoryContainer.add(actionPanel);
+
+        actionPanel.add(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                if (StringUtils.isNotBlank(custom.getModelObject())) {
+                    final Map.Entry<EventCategoryTO, AuditElements.Result> parsed =
+                            AuditLoggerName.parseEventCategory(custom.getModelObject());
+
+                    final String eventString = AuditLoggerName.buildEvent(
+                            parsed.getKey().getType(),
+                            null,
+                            null,
+                            parsed.getKey().getEvents().isEmpty()
+                                    ? StringUtils.EMPTY : parsed.getKey().getEvents().iterator().next(),
+                            parsed.getValue());
+
+                    custom.setModelObject(StringUtils.EMPTY);
+                    send(LoggerCategoryPanel.this.getPage(), Broadcast.BREADTH, new EventSelectionChanged(
+                            target,
+                            Collections.<String>singleton(eventString),
+                            Collections.<String>emptySet()));
+                    target.add(categoryContainer);
+                }
+            }
+        }, ActionLink.ActionType.CREATE, pageId, true);
+
+        actionPanel.add(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435502L;
+
+            @Override
+            public void onClick(AjaxRequestTarget target) {
+                if (StringUtils.isNotBlank(custom.getModelObject())) {
+                    final Map.Entry<EventCategoryTO, AuditElements.Result> parsed =
+                            AuditLoggerName.parseEventCategory(custom.getModelObject());
+
+                    final String eventString = AuditLoggerName.buildEvent(
+                            parsed.getKey().getType(),
+                            null,
+                            null,
+                            parsed.getKey().getEvents().isEmpty()
+                                    ? StringUtils.EMPTY : parsed.getKey().getEvents().iterator().next(),
+                            parsed.getValue());
+
+                    custom.setModelObject(StringUtils.EMPTY);
+                    send(LoggerCategoryPanel.this.getPage(), Broadcast.BREADTH, new EventSelectionChanged(
+                            target,
+                            Collections.<String>emptySet(),
+                            Collections.<String>singleton(eventString)));
+                    target.add(categoryContainer);
+                }
+            }
+        }, ActionLink.ActionType.DELETE, pageId, true);
+
+        actionPanel.setVisible(false);
+        actionPanel.setEnabled(false);
+
+        eventsContainer.add(new EventSelectionPanel("eventsPanel", eventCategoryTO, model) {
+
+            private static final long serialVersionUID = 3513194801190026082L;
+
+            @Override
+            protected void onEventAction(final IEvent<?> event) {
+                LoggerCategoryPanel.this.onEventAction(event);
+            }
+        });
+    }
+
+    private List<String> filter(
+            final List<EventCategoryTO> eventCategoryTOs, final EventCategoryType type) {
+        final Set<String> res = new HashSet<String>();
+
+        for (EventCategoryTO eventCategory : eventCategoryTOs) {
+            if (type == eventCategory.getType() && StringUtils.isNotEmpty(eventCategory.getCategory())) {
+                res.add(eventCategory.getCategory());
+            }
+        }
+
+        final List<String> filtered = new ArrayList<String>(res);
+        Collections.sort(filtered);
+        return filtered;
+    }
+
+    private List<String> filter(
+            final List<EventCategoryTO> eventCategoryTOs, final EventCategoryType type, final String category) {
+        final Set<String> res = new HashSet<String>();
+
+        for (EventCategoryTO eventCategory : eventCategoryTOs) {
+            if (type == eventCategory.getType() && StringUtils.equals(category, eventCategory.getCategory())
+                    && StringUtils.isNotEmpty(eventCategory.getSubcategory())) {
+                res.add(eventCategory.getSubcategory());
+            }
+        }
+
+        final List<String> filtered = new ArrayList<String>(res);
+        Collections.sort(filtered);
+        return filtered;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void onEvent(final IEvent<?> event) {
+        if (event.getPayload() instanceof ChangeCategoryEvent) {
+            // update objects ....
+            eventCategoryTO.getEvents().clear();
+
+            final ChangeCategoryEvent change = (ChangeCategoryEvent) event.getPayload();
+
+            final Panel changedPanel = change.getChangedPanel();
+            if ("type".equals(changedPanel.getId())) {
+                eventCategoryTO.setType(type.getModelObject());
+                eventCategoryTO.setCategory(null);
+                eventCategoryTO.setSubcategory(null);
+
+                if (type.getModelObject() == EventCategoryType.CUSTOM) {
+                    category.setChoices(Collections.<String>emptyList());
+                    subcategory.setChoices(Collections.<String>emptyList());
+                    category.setEnabled(false);
+                    subcategory.setEnabled(false);
+                    custom.setVisible(true);
+                    custom.setEnabled(true);
+                    actionPanel.setVisible(true);
+                    actionPanel.setEnabled(true);
+
+                } else {
+                    category.setChoices(filter(eventCategoryTOs, type.getModelObject()));
+                    subcategory.setChoices(Collections.<String>emptyList());
+                    category.setEnabled(true);
+                    subcategory.setEnabled(true);
+                    custom.setVisible(false);
+                    custom.setEnabled(false);
+                    actionPanel.setVisible(false);
+                    actionPanel.setEnabled(false);
+                }
+                change.getTarget().add(categoryContainer);
+            } else if ("category".equals(changedPanel.getId())) {
+                subcategory.setChoices(filter(eventCategoryTOs, type.getModelObject(), category.getModelObject()));
+                eventCategoryTO.setCategory(category.getModelObject());
+                eventCategoryTO.setSubcategory(null);
+                change.getTarget().add(categoryContainer);
+            } else {
+                eventCategoryTO.setSubcategory(subcategory.getModelObject());
+            }
+
+            updateEventsContainer(change.getTarget());
+        } else if (event.getPayload() instanceof InspectSelectedEvent) {
+            // update objects ....
+            eventCategoryTO.getEvents().clear();
+
+            final InspectSelectedEvent inspectSelectedEvent = (InspectSelectedEvent) event.getPayload();
+
+            final Map.Entry<EventCategoryTO, AuditElements.Result> categoryEvent =
+                    AuditLoggerName.parseEventCategory(inspectSelectedEvent.getEvent());
+
+            eventCategoryTO.setType(categoryEvent.getKey().getType());
+            category.setChoices(filter(eventCategoryTOs, type.getModelObject()));
+
+            eventCategoryTO.setCategory(categoryEvent.getKey().getCategory());
+            subcategory.setChoices(filter(eventCategoryTOs, type.getModelObject(), category.getModelObject()));
+
+            eventCategoryTO.setSubcategory(categoryEvent.getKey().getSubcategory());
+
+            if (categoryEvent.getKey().getType() == EventCategoryType.CUSTOM) {
+                custom.setModelObject(AuditLoggerName.buildEvent(
+                        categoryEvent.getKey().getType(),
+                        categoryEvent.getKey().getCategory(),
+                        categoryEvent.getKey().getSubcategory(),
+                        categoryEvent.getKey().getEvents().isEmpty()
+                                ? StringUtils.EMPTY : categoryEvent.getKey().getEvents().iterator().next(),
+                        categoryEvent.getValue()));
+
+                category.setEnabled(false);
+                subcategory.setEnabled(false);
+                custom.setVisible(true);
+                custom.setEnabled(true);
+                actionPanel.setVisible(true);
+                actionPanel.setEnabled(true);
+            } else {
+                category.setEnabled(true);
+                subcategory.setEnabled(true);
+                custom.setVisible(false);
+                custom.setEnabled(false);
+                actionPanel.setVisible(false);
+                actionPanel.setEnabled(false);
+            }
+
+            inspectSelectedEvent.getTarget().add(categoryContainer);
+            updateEventsContainer(inspectSelectedEvent.getTarget());
+        }
+    }
+
+    private void setEvents() {
+        final Iterator<EventCategoryTO> itor = eventCategoryTOs.iterator();
+        while (itor.hasNext() && eventCategoryTO.getEvents().isEmpty()) {
+            final EventCategoryTO eventCategory = itor.next();
+            if (eventCategory.getType() == eventCategoryTO.getType()
+                    && StringUtils.equals(eventCategory.getCategory(), eventCategoryTO.getCategory())
+                    && StringUtils.equals(eventCategory.getSubcategory(), eventCategoryTO.getSubcategory())) {
+                eventCategoryTO.getEvents().addAll(eventCategory.getEvents());
+            }
+        }
+    }
+
+    private class ChangeCategoryEvent {
+
+        private final AjaxRequestTarget target;
+
+        private final Panel changedPanel;
+
+        public ChangeCategoryEvent(final AjaxRequestTarget target, final Panel changedPanel) {
+            this.target = target;
+            this.changedPanel = changedPanel;
+        }
+
+        public AjaxRequestTarget getTarget() {
+            return target;
+        }
+
+        public Panel getChangedPanel() {
+            return changedPanel;
+        }
+    }
+
+    /**
+     * To be extended in order to add actions on events.
+     *
+     * @param event event.
+     */
+    protected void onEventAction(final IEvent<?> event) {
+        // nothing by default
+    }
+
+    private void authorizeList() {
+        for (String role : getListRoles()) {
+            MetaDataRoleAuthorizationStrategy.authorize(selectedEventsPanel, RENDER, role);
+        }
+    }
+
+    private void authorizeChanges() {
+        for (String role : getChangeRoles()) {
+            MetaDataRoleAuthorizationStrategy.authorize(categoryContainer, RENDER, role);
+            MetaDataRoleAuthorizationStrategy.authorize(eventsContainer, RENDER, role);
+        }
+    }
+
+    private void updateEventsContainer(final AjaxRequestTarget target) {
+        setEvents();
+
+        eventsContainer.addOrReplace(new EventSelectionPanel("eventsPanel", eventCategoryTO, model) {
+
+            private static final long serialVersionUID = 3513194801190026082L;
+
+            @Override
+            public void onEventAction(final IEvent<?> event) {
+                LoggerCategoryPanel.this.onEventAction(event);
+            }
+        });
+        target.add(eventsContainer);
+    }
+
+    protected abstract String[] getListRoles();
+
+    protected abstract String[] getChangeRoles();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java
new file mode 100644
index 0000000..fb00dcf
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java
@@ -0,0 +1,256 @@
+/*
+ * 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.panels;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.swing.tree.DefaultMutableTreeNode;
+import org.apache.syncope.client.console.commons.Mode;
+import org.apache.syncope.client.console.commons.RoleTreeBuilder;
+import org.apache.syncope.client.console.commons.RoleUtils;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.client.console.pages.MembershipModalPage;
+import org.apache.syncope.client.console.pages.UserModalPage;
+import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
+import org.apache.syncope.client.console.wicket.ajax.markup.html.IndicatingOnConfirmAjaxLink;
+import org.apache.syncope.client.console.wicket.markup.html.tree.DefaultMutableTreeNodeExpansion;
+import org.apache.syncope.client.console.wicket.markup.html.tree.DefaultMutableTreeNodeExpansionModel;
+import org.apache.syncope.client.console.wicket.markup.html.tree.TreeRoleProvider;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.wicket.Component;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.extensions.markup.html.repeater.tree.DefaultNestedTree;
+import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
+import org.apache.wicket.extensions.markup.html.repeater.tree.NestedTree;
+import org.apache.wicket.extensions.markup.html.repeater.tree.content.Folder;
+import org.apache.wicket.extensions.markup.html.repeater.tree.theme.WindowsTheme;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class MembershipsPanel extends Panel {
+
+    private static final long serialVersionUID = -2559791301973107191L;
+
+    @SpringBean
+    private RoleTreeBuilder roleTreeBuilder;
+
+    private final ListView<MembershipTO> membView;
+
+    private final UserTO userTO;
+
+    private final StatusPanel statusPanel;
+
+    private final NestedTree<DefaultMutableTreeNode> tree;
+
+    public MembershipsPanel(final String id, final UserTO userTO, final Mode mode,
+            final StatusPanel statusPanel, final PageReference pageRef) {
+
+        super(id);
+        this.userTO = userTO;
+        this.statusPanel = statusPanel;
+
+        final WebMarkupContainer membershipsContainer = new WebMarkupContainer("membershipsContainer");
+        membershipsContainer.setOutputMarkupId(true);
+        add(membershipsContainer);
+
+        final ModalWindow membWin = new ModalWindow("membershipWin");
+        membWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        membWin.setCookieName("create-membership-modal");
+        add(membWin);
+
+        final ITreeProvider<DefaultMutableTreeNode> treeProvider = new TreeRoleProvider(roleTreeBuilder, true);
+        final DefaultMutableTreeNodeExpansionModel treeModel = new DefaultMutableTreeNodeExpansionModel();
+
+        tree = new DefaultNestedTree<DefaultMutableTreeNode>("treeTable", treeProvider, treeModel) {
+
+            private static final long serialVersionUID = 7137658050662575546L;
+
+            @Override
+            protected Component newContentComponent(final String id, final IModel<DefaultMutableTreeNode> node) {
+                final DefaultMutableTreeNode treeNode = node.getObject();
+                final RoleTO roleTO = (RoleTO) treeNode.getUserObject();
+
+                return new Folder<DefaultMutableTreeNode>(id, MembershipsPanel.this.tree, node) {
+
+                    private static final long serialVersionUID = 9046323319920426493L;
+
+                    @Override
+                    protected boolean isClickable() {
+                        return true;
+                    }
+
+                    @Override
+                    protected IModel<?> newLabelModel(final IModel<DefaultMutableTreeNode> model) {
+                        return new Model<String>(roleTO.getDisplayName());
+                    }
+
+                    @Override
+                    protected void onClick(final AjaxRequestTarget target) {
+                        if (roleTO.getKey() > 0) {
+                            membWin.setPageCreator(new ModalWindow.PageCreator() {
+
+                                private static final long serialVersionUID = 7661763358801821185L;
+
+                                @Override
+                                public Page createPage() {
+                                    PageReference pageRef = getPage().getPageReference();
+
+                                    for (MembershipTO membTO : membView.getList()) {
+                                        if (membTO.getRoleId() == roleTO.getKey()) {
+                                            return new MembershipModalPage(pageRef, membWin, membTO, mode);
+                                        }
+                                    }
+                                    MembershipTO membTO = new MembershipTO();
+                                    membTO.setRoleId(roleTO.getKey());
+                                    membTO.setRoleName(roleTO.getName());
+
+                                    return new MembershipModalPage(pageRef, membWin, membTO, mode);
+                                }
+                            });
+                            membWin.show(target);
+                        }
+                    }
+                };
+            }
+        };
+        tree.add(new WindowsTheme());
+        tree.setOutputMarkupId(true);
+
+        DefaultMutableTreeNodeExpansion.get().expandAll();
+
+        this.add(tree);
+
+        membView = new ListView<MembershipTO>("memberships",
+                new PropertyModel<List<? extends MembershipTO>>(userTO, "memberships")) {
+
+                    private static final long serialVersionUID = 9101744072914090143L;
+
+                    @Override
+                    protected void populateItem(final ListItem<MembershipTO> item) {
+                        final MembershipTO membershipTO = (MembershipTO) item.getDefaultModelObject();
+
+                        item.add(new Label("roleId", new Model<Long>(membershipTO.getRoleId())));
+                        item.add(new Label("roleName", new Model<String>(membershipTO.getRoleName())));
+
+                        AjaxLink editLink = new ClearIndicatingAjaxLink("editLink", pageRef) {
+
+                            private static final long serialVersionUID = -7978723352517770644L;
+
+                            @Override
+                            protected void onClickInternal(final AjaxRequestTarget target) {
+                                membWin.setPageCreator(new ModalWindow.PageCreator() {
+
+                                    private static final long serialVersionUID = -7834632442532690940L;
+
+                                    @Override
+                                    public Page createPage() {
+                                        return new MembershipModalPage(getPage().getPageReference(), membWin,
+                                                membershipTO, mode);
+
+                                    }
+                                });
+                                membWin.show(target);
+                            }
+                        };
+                        item.add(editLink);
+
+                        AjaxLink deleteLink = new IndicatingOnConfirmAjaxLink("deleteLink", pageRef) {
+
+                            private static final long serialVersionUID = -7978723352517770644L;
+
+                            @Override
+                            protected void onClickInternal(final AjaxRequestTarget target) {
+                                userTO.getMemberships().remove(membershipTO);
+                                ((UserModalPage) getPage()).getUserTO().getMemberships().remove(membershipTO);
+                                target.add(membershipsContainer);
+
+                                RoleTO roleTO = RoleUtils.findRole(roleTreeBuilder, membershipTO.getRoleId());
+                                Set<String> resourcesToRemove = roleTO == null
+                                        ? Collections.<String>emptySet() : roleTO.getResources();
+                                if (!resourcesToRemove.isEmpty()) {
+                                    Set<String> resourcesAssignedViaMembership = new HashSet<String>();
+                                    for (MembershipTO membTO : userTO.getMemberships()) {
+                                        roleTO = RoleUtils.findRole(roleTreeBuilder, membTO.getRoleId());
+                                        if (roleTO != null) {
+                                            resourcesAssignedViaMembership.addAll(roleTO.getResources());
+                                        }
+                                    }
+                                    resourcesToRemove.removeAll(resourcesAssignedViaMembership);
+                                    resourcesToRemove.removeAll(userTO.getResources());
+                                }
+
+                                StatusUtils.update(
+                                        userTO, statusPanel, target, Collections.<String>emptySet(), resourcesToRemove);
+                            }
+                        };
+                        item.add(deleteLink);
+                    }
+                };
+
+        membershipsContainer.add(membView);
+
+        setWindowClosedCallback(membWin, membershipsContainer);
+    }
+
+    private void setWindowClosedCallback(final ModalWindow window, final WebMarkupContainer container) {
+        window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
+
+            private static final long serialVersionUID = 8804221891699487139L;
+
+            @Override
+            public void onClose(final AjaxRequestTarget target) {
+                final UserTO updatedUserTO = ((UserModalPage) getPage()).getUserTO();
+                if (!userTO.equals(updatedUserTO)) {
+                    if (updatedUserTO.getMemberships().size() > userTO.getMemberships().size()) {
+                        Set<Long> diff = new HashSet<Long>(updatedUserTO.getMembershipMap().keySet());
+                        diff.removeAll(userTO.getMembershipMap().keySet());
+
+                        Set<String> resourcesToAdd = new HashSet<String>();
+                        for (Long diffMembId : diff) {
+                            long roleId = updatedUserTO.getMembershipMap().get(diffMembId).getRoleId();
+                            RoleTO roleTO = RoleUtils.findRole(roleTreeBuilder, roleId);
+                            resourcesToAdd.addAll(roleTO.getResources());
+                            StatusUtils.update(
+                                    userTO, statusPanel, target, resourcesToAdd, Collections.<String>emptySet());
+                        }
+                    }
+
+                    MembershipsPanel.this.userTO.getMemberships().clear();
+                    MembershipsPanel.this.userTO.getMemberships().addAll(updatedUserTO.getMemberships());
+                    target.add(container);
+                }
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationPanel.java
new file mode 100644
index 0000000..8624d26
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationPanel.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.ajax.AjaxEventBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.feedback.FeedbackMessage;
+import org.apache.wicket.feedback.IFeedbackMessageFilter;
+import org.apache.wicket.markup.html.panel.FeedbackPanel;
+import org.apache.wicket.model.Model;
+
+public class NotificationPanel extends FeedbackPanel {
+
+    private static final long serialVersionUID = 5895940553202128621L;
+
+    private static final String CSS_CLASS = "notificationpanel";
+
+    private static final String DEFAULT_ADDITIONAL_CSS_CLASS = "notificationpanel_top_right";
+
+    private final String additionalCSSClass;
+
+    public NotificationPanel(final String id) {
+        this(id, null, null);
+    }
+
+    public NotificationPanel(final String id, final String additionalCSSClass,
+            final IFeedbackMessageFilter feedbackMessageFilter) {
+
+        super(id, feedbackMessageFilter);
+
+        this.add(new AjaxEventBehavior(Constants.ON_CLICK) {
+
+            private static final long serialVersionUID = -7133385027739964990L;
+
+            @Override
+            protected void onEvent(final AjaxRequestTarget target) {
+                target.appendJavaScript(
+                        "setTimeout(\"$('div#" + getMarkupId() + "').fadeOut('normal')\", 0);");
+            }
+        });
+
+        this.additionalCSSClass = StringUtils.isBlank(additionalCSSClass)
+                ? DEFAULT_ADDITIONAL_CSS_CLASS
+                : additionalCSSClass;
+
+        // set custom markup id and ouput it, to find the component later on in the js function
+        setMarkupId(id);
+        setOutputMarkupId(true);
+
+        // Add the additional cssClass and hide the element by default
+        add(new AttributeModifier("class", new Model<String>(CSS_CLASS + " " + this.additionalCSSClass)));
+        add(new AttributeModifier("style", new Model<String>("opacity: 0;")));
+    }
+
+    /**
+     * Method to refresh the notification panel.
+     *
+     * If there are any feedback messages for the user, find the gravest level, format the notification panel
+     * accordingly and show it.
+     *
+     * @param target AjaxRequestTarget to add panel and the calling javascript function
+     */
+    public void refresh(final AjaxRequestTarget target) {
+        // any feedback at all in the current form?
+        if (anyMessage()) {
+            int highestFeedbackLevel = FeedbackMessage.INFO;
+
+            // any feedback with the given level?
+            if (anyMessage(FeedbackMessage.WARNING)) {
+                highestFeedbackLevel = FeedbackMessage.WARNING;
+            }
+            if (anyMessage(FeedbackMessage.ERROR)) {
+                highestFeedbackLevel = FeedbackMessage.ERROR;
+            }
+
+            // add the css classes to the notification panel, 
+            // including the border css which represents the highest level of feedback
+            add(new AttributeModifier("class",
+                    new Model<String>(CSS_CLASS
+                            + " " + additionalCSSClass
+                            + " notificationpanel_border_" + highestFeedbackLevel)));
+
+            // refresh the panel and call the js function with the panel markup id 
+            // and the total count of messages
+            target.add(this);
+            if (anyMessage(FeedbackMessage.ERROR)) {
+                target.appendJavaScript(
+                        "$('div#" + getMarkupId() + "').fadeTo('normal', 1.0);");
+            } else {
+                target.appendJavaScript(
+                        "showNotification('" + getMarkupId() + "', " + getCurrentMessages().size() + ");");
+            }
+        }
+    }
+
+    @Override
+    protected String getCSSClass(final FeedbackMessage message) {
+        return "notificationpanel_row_" + message.getLevelAsString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java
new file mode 100644
index 0000000..d7f52e1
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/NotificationTasks.java
@@ -0,0 +1,254 @@
+/*
+ * 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.panels;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.pages.NotificationTaskModalPage;
+import org.apache.syncope.client.console.pages.Tasks;
+import org.apache.syncope.client.console.pages.Tasks.TasksProvider;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.NotificationTaskTO;
+import org.apache.wicket.Component;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.StringResourceModel;
+import org.apache.wicket.request.http.WebResponse;
+
+public class NotificationTasks extends AbstractTasks {
+
+    private static final long serialVersionUID = 4984337552918213290L;
+
+    private int paginatorRows;
+
+    private WebMarkupContainer container;
+
+    private boolean operationResult = false;
+
+    private ModalWindow window;
+
+    private AjaxDataTablePanel<AbstractTaskTO, String> table;
+
+    public NotificationTasks(final String id, final PageReference pageRef) {
+        super(id, pageRef);
+
+        container = new WebMarkupContainer("container");
+        container.setOutputMarkupId(true);
+        add(container);
+
+        add(window = new ModalWindow("taskWin"));
+
+        paginatorRows = prefMan.getPaginatorRows(getWebRequest(), Constants.PREF_NOTIFICATION_TASKS_PAGINATOR_ROWS);
+
+        table = Tasks.updateTaskTable(
+                getColumns(),
+                new TasksProvider<NotificationTaskTO>(restClient, paginatorRows, getId(), NotificationTaskTO.class),
+                container,
+                0,
+                pageRef,
+                restClient);
+
+        container.add(table);
+
+        window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
+
+            private static final long serialVersionUID = 8804221891699487139L;
+
+            @Override
+            public void onClose(final AjaxRequestTarget target) {
+                target.add(container);
+                if (operationResult) {
+                    info(getString(Constants.OPERATION_SUCCEEDED));
+                    target.add(getPage().get(Constants.FEEDBACK));
+                    operationResult = false;
+                }
+            }
+        });
+
+        window.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        window.setInitialHeight(WIN_HEIGHT);
+        window.setInitialWidth(WIN_WIDTH);
+        window.setCookieName(VIEW_TASK_WIN_COOKIE_NAME);
+
+        @SuppressWarnings("rawtypes")
+        final Form paginatorForm = new Form("PaginatorForm");
+
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        final DropDownChoice rowsChooser = new DropDownChoice("rowsChooser", new PropertyModel(this, "paginatorRows"),
+                prefMan.getPaginatorChoices());
+
+        rowsChooser.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                prefMan.set(getWebRequest(), (WebResponse) getResponse(),
+                        Constants.PREF_NOTIFICATION_TASKS_PAGINATOR_ROWS, String.valueOf(paginatorRows));
+
+                table = Tasks.updateTaskTable(
+                        getColumns(),
+                        new TasksProvider<NotificationTaskTO>(restClient, paginatorRows, getId(),
+                                NotificationTaskTO.class),
+                        container,
+                        table == null ? 0 : (int) table.getCurrentPage(),
+                        pageRef,
+                        restClient);
+
+                target.add(container);
+            }
+        });
+
+        paginatorForm.add(rowsChooser);
+        add(paginatorForm);
+    }
+
+    private List<IColumn<AbstractTaskTO, String>> getColumns() {
+        final List<IColumn<AbstractTaskTO, String>> columns = new ArrayList<>();
+
+        columns.add(new PropertyColumn<AbstractTaskTO, String>(
+                new StringResourceModel("key", this, null), "key", "key"));
+        columns.add(new PropertyColumn<AbstractTaskTO, String>(
+                new StringResourceModel("sender", this, null), "sender", "sender"));
+        columns.add(new PropertyColumn<AbstractTaskTO, String>(
+                new StringResourceModel("recipients", this, null), "recipients", "recipients"));
+        columns.add(new PropertyColumn<AbstractTaskTO, String>(
+                new StringResourceModel("subject", this, null), "subject", "subject"));
+        columns.add(new PropertyColumn<AbstractTaskTO, String>(
+                new StringResourceModel("traceLevel", this, null), "traceLevel", "traceLevel"));
+        columns.add(new PropertyColumn<AbstractTaskTO, String>(
+                new StringResourceModel("latestExecStatus", this, null), "latestExecStatus", "latestExecStatus"));
+
+        columns.add(new ActionColumn<AbstractTaskTO, String>(new StringResourceModel("actions", this, null, "")) {
+
+            private static final long serialVersionUID = 2054811145491901166L;
+
+            @Override
+            public ActionLinksPanel getActions(final String componentId, final IModel<AbstractTaskTO> model) {
+
+                final AbstractTaskTO taskTO = model.getObject();
+
+                final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, pageRef);
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+
+                        window.setPageCreator(new ModalWindow.PageCreator() {
+
+                            private static final long serialVersionUID = -7834632442532690940L;
+
+                            @Override
+                            public Page createPage() {
+                                return new NotificationTaskModalPage(taskTO);
+                            }
+                        });
+
+                        window.show(target);
+                    }
+                }, ActionLink.ActionType.EDIT, TASKS);
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        try {
+                            restClient.startExecution(taskTO.getKey(), false);
+                            getSession().info(getString(Constants.OPERATION_SUCCEEDED));
+                        } catch (SyncopeClientException scce) {
+                            error(scce.getMessage());
+                        }
+
+                        ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
+                        target.add(container);
+                    }
+                }, ActionLink.ActionType.EXECUTE, TASKS);
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        try {
+                            restClient.delete(taskTO.getKey(), NotificationTaskTO.class);
+                            info(getString(Constants.OPERATION_SUCCEEDED));
+                        } catch (SyncopeClientException scce) {
+                            error(scce.getMessage());
+                        }
+                        target.add(container);
+                        ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
+                    }
+                }, ActionLink.ActionType.DELETE, TASKS);
+
+                return panel;
+            }
+
+            @Override
+            public Component getHeader(String componentId) {
+                final ActionLinksPanel panel = new ActionLinksPanel(componentId, new Model(), pageRef);
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        if (target != null) {
+                            target.add(table);
+                        }
+                    }
+                }, ActionLink.ActionType.RELOAD, TASKS, "list");
+
+                return panel;
+            }
+        });
+
+        return columns;
+    }
+
+    @Override
+    public void onEvent(final IEvent<?> event) {
+        if (event.getPayload() instanceof AbstractSearchResultPanel.EventDataWrapper) {
+            ((AbstractSearchResultPanel.EventDataWrapper) event.getPayload()).getTarget().add(container);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/PlainAttrsPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/PlainAttrsPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/PlainAttrsPanel.java
new file mode 100644
index 0000000..8e42318
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/PlainAttrsPanel.java
@@ -0,0 +1,395 @@
+/*
+ * 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.panels;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.AttrLayoutType;
+import org.apache.syncope.client.console.commons.JexlHelpUtil;
+import org.apache.syncope.client.console.commons.Mode;
+import org.apache.syncope.client.console.panels.AttrTemplatesPanel.RoleAttrTemplatesChange;
+import org.apache.syncope.client.console.rest.ConfigurationRestClient;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.client.console.rest.SchemaRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.BinaryFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.DateTextFieldPanel;
+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.client.console.wicket.markup.html.form.SpinnerFieldPanel;
+import org.apache.syncope.client.console.wicket.markup.html.list.AltListView;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ConfTO;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.AttrSchemaType;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class PlainAttrsPanel extends Panel {
+
+    private static final long serialVersionUID = 552437609667518888L;
+
+    @SpringBean
+    private SchemaRestClient schemaRestClient;
+
+    @SpringBean
+    private ConfigurationRestClient confRestClient;
+
+    @SpringBean
+    private RoleRestClient roleRestClient;
+
+    private final AbstractAttributableTO entityTO;
+
+    private final Mode mode;
+
+    private final AttrTemplatesPanel attrTemplates;
+
+    private Map<String, PlainSchemaTO> schemas = new LinkedHashMap<>();
+
+    public <T extends AbstractAttributableTO> PlainAttrsPanel(final String id, final T entityTO,
+            final Form<?> form, final Mode mode) {
+
+        this(id, entityTO, form, mode, null);
+    }
+
+    public <T extends AbstractAttributableTO> PlainAttrsPanel(final String id, final T entityTO,
+            final Form<?> form, final Mode mode, final AttrTemplatesPanel attrTemplates) {
+
+        super(id);
+        this.entityTO = entityTO;
+        this.mode = mode;
+        this.attrTemplates = attrTemplates;
+        this.setOutputMarkupId(true);
+
+        setSchemas();
+        setAttrs();
+
+        add(new AltListView<AttrTO>("schemas", new PropertyModel<List<? extends AttrTO>>(entityTO, "attrs")) {
+
+            private static final long serialVersionUID = 9101744072914090143L;
+
+            @Override
+            @SuppressWarnings({ "unchecked", "rawtypes" })
+            protected void populateItem(final ListItem<AttrTO> item) {
+                final AttrTO attributeTO = (AttrTO) item.getDefaultModelObject();
+
+                final WebMarkupContainer jexlHelp = JexlHelpUtil.getJexlHelpWebContainer("jexlHelp");
+
+                final AjaxLink<Void> questionMarkJexlHelp = JexlHelpUtil.getAjaxLink(jexlHelp, "questionMarkJexlHelp");
+                item.add(questionMarkJexlHelp);
+                questionMarkJexlHelp.add(jexlHelp);
+
+                if (mode != Mode.TEMPLATE) {
+                    questionMarkJexlHelp.setVisible(false);
+                }
+
+                item.add(new Label("name", attributeTO.getSchema()));
+
+                final FieldPanel panel = getFieldPanel(schemas.get(attributeTO.getSchema()), form, attributeTO);
+
+                if (mode == Mode.TEMPLATE || !schemas.get(attributeTO.getSchema()).isMultivalue()) {
+                    item.add(panel);
+                } else {
+                    item.add(new MultiFieldPanel<String>(
+                            "panel", new PropertyModel<List<String>>(attributeTO, "values"), panel));
+                }
+            }
+        }
+        );
+    }
+
+    private void setSchemas() {
+        AttrTO attrLayout = null;
+        List<PlainSchemaTO> schemaTOs;
+
+        if (entityTO instanceof RoleTO) {
+            final RoleTO roleTO = (RoleTO) entityTO;
+
+            attrLayout = confRestClient.readAttrLayout(AttrLayoutType.valueOf(mode, AttributableType.ROLE));
+            schemaTOs = schemaRestClient.getSchemas(AttributableType.ROLE);
+            Set<String> allowed;
+            if (attrTemplates == null) {
+                allowed = new HashSet<>(roleTO.getRPlainAttrTemplates());
+            } else {
+                allowed = new HashSet<>(attrTemplates.getSelected(AttrTemplatesPanel.Type.rPlainAttrTemplates));
+                if (roleTO.isInheritTemplates() && roleTO.getParent() != 0) {
+                    allowed.addAll(roleRestClient.read(roleTO.getParent()).getRPlainAttrTemplates());
+                }
+            }
+            schemaRestClient.filter(schemaTOs, allowed, true);
+        } else if (entityTO instanceof UserTO) {
+            attrLayout = confRestClient.readAttrLayout(AttrLayoutType.valueOf(mode, AttributableType.USER));
+            schemaTOs = schemaRestClient.getSchemas(AttributableType.USER);
+        } else if (entityTO instanceof MembershipTO) {
+            attrLayout = confRestClient.readAttrLayout(AttrLayoutType.valueOf(mode, AttributableType.MEMBERSHIP));
+            schemaTOs = schemaRestClient.getSchemas(AttributableType.MEMBERSHIP);
+            Set<String> allowed = new HashSet<>(
+                    roleRestClient.read(((MembershipTO) entityTO).getRoleId()).getMPlainAttrTemplates());
+            schemaRestClient.filter(schemaTOs, allowed, true);
+        } else {
+            schemas = new TreeMap<>();
+            schemaTOs = schemaRestClient.getSchemas(AttributableType.CONFIGURATION);
+            for (Iterator<PlainSchemaTO> it = schemaTOs.iterator(); it.hasNext();) {
+                PlainSchemaTO schemaTO = it.next();
+                for (AttrLayoutType type : AttrLayoutType.values()) {
+                    if (type.getConfKey().equals(schemaTO.getKey())) {
+                        it.remove();
+                    }
+                }
+            }
+        }
+
+        schemas.clear();
+
+        if (attrLayout != null && mode != Mode.TEMPLATE && !(entityTO instanceof ConfTO)) {
+            // 1. remove attributes not selected for display
+            schemaRestClient.filter(schemaTOs, 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(schemaTOs, new Comparator<PlainSchemaTO>() {
+
+                @Override
+                public int compare(final PlainSchemaTO schema1, final PlainSchemaTO 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 (PlainSchemaTO schemaTO : schemaTOs) {
+            schemas.put(schemaTO.getKey(), schemaTO);
+        }
+    }
+
+    private void setAttrs() {
+        final List<AttrTO> entityData = new ArrayList<>();
+
+        final Map<String, AttrTO> attrMap = entityTO.getPlainAttrMap();
+
+        for (PlainSchemaTO schema : schemas.values()) {
+            final AttrTO attributeTO = new AttrTO();
+            attributeTO.setSchema(schema.getKey());
+
+            if (attrMap.get(schema.getKey()) == null || attrMap.get(schema.getKey()).getValues().isEmpty()) {
+                attributeTO.getValues().add("");
+
+                // is important to set readonly only after values setting
+                attributeTO.setReadonly(schema.isReadonly());
+            } else {
+                attributeTO.getValues().addAll(attrMap.get(schema.getKey()).getValues());
+            }
+            entityData.add(attributeTO);
+        }
+
+        entityTO.getPlainAttrs().clear();
+        entityTO.getPlainAttrs().addAll(entityData);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    private FieldPanel getFieldPanel(final PlainSchemaTO schemaTO, final Form form, final AttrTO attributeTO) {
+        final boolean required = mode == Mode.TEMPLATE
+                ? false
+                : schemaTO.getMandatoryCondition().equalsIgnoreCase("true");
+
+        final boolean readOnly = mode == Mode.TEMPLATE ? false : schemaTO.isReadonly();
+
+        final AttrSchemaType type = mode == Mode.TEMPLATE ? AttrSchemaType.String : schemaTO.getType();
+
+        final FieldPanel panel;
+        switch (type) {
+            case Boolean:
+                panel = new AjaxCheckBoxPanel("panel", schemaTO.getKey(), new Model<Boolean>());
+                panel.setRequired(required);
+                break;
+
+            case Date:
+                final String dataPattern = schemaTO.getConversionPattern() == null
+                        ? SyncopeConstants.DEFAULT_DATE_PATTERN
+                        : schemaTO.getConversionPattern();
+
+                if (dataPattern.contains("H")) {
+                    panel = new DateTimeFieldPanel("panel", schemaTO.getKey(), new Model<Date>(), dataPattern);
+
+                    if (required) {
+                        panel.addRequiredLabel();
+                        ((DateTimeFieldPanel) panel).setFormValidator(form);
+                    }
+                    panel.setStyleSheet("ui-widget-content ui-corner-all");
+                } else {
+                    panel = new DateTextFieldPanel("panel", schemaTO.getKey(), new Model<Date>(), dataPattern);
+
+                    if (required) {
+                        panel.addRequiredLabel();
+                    }
+                }
+                break;
+
+            case Enum:
+                panel = new AjaxDropDownChoicePanel<String>("panel", schemaTO.getKey(), new Model<String>());
+                ((AjaxDropDownChoicePanel<String>) panel).setChoices(getEnumeratedValues(schemaTO));
+
+                if (StringUtils.isNotBlank(schemaTO.getEnumerationKeys())) {
+                    ((AjaxDropDownChoicePanel) panel).setChoiceRenderer(new IChoiceRenderer<String>() {
+
+                        private static final long serialVersionUID = -3724971416312135885L;
+
+                        private final Map<String, String> valueMap = getEnumeratedKeyValues(schemaTO);
+
+                        @Override
+                        public String getDisplayValue(final String value) {
+                            return valueMap.get(value) == null ? value : valueMap.get(value);
+                        }
+
+                        @Override
+                        public String getIdValue(final String value, final int i) {
+                            return value;
+                        }
+                    });
+                }
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+                break;
+
+            case Long:
+                panel = new SpinnerFieldPanel<Long>("panel", schemaTO.getKey(),
+                        Long.class, new Model<Long>(), null, null);
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+                break;
+
+            case Double:
+                panel = new SpinnerFieldPanel<Double>("panel", schemaTO.getKey(),
+                        Double.class, new Model<Double>(), null, null);
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+                break;
+
+            case Binary:
+                panel = new BinaryFieldPanel("panel", schemaTO.getKey(), new Model<String>(),
+                        schemas.containsKey(schemaTO.getKey())
+                                ? schemas.get(schemaTO.getKey()).getMimeType()
+                                : null);
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+                break;
+
+            default:
+                panel = new AjaxTextFieldPanel("panel", schemaTO.getKey(), new Model<String>());
+
+                if (required) {
+                    panel.addRequiredLabel();
+                }
+        }
+
+        panel.setReadOnly(readOnly);
+        panel.setNewModel(attributeTO.getValues());
+
+        return panel;
+    }
+
+    private Map<String, String> getEnumeratedKeyValues(final PlainSchemaTO schemaTO) {
+        final Map<String, String> res = new HashMap<>();
+
+        final String[] values = StringUtils.isBlank(schemaTO.getEnumerationValues())
+                ? new String[0]
+                : schemaTO.getEnumerationValues().split(SyncopeConstants.ENUM_VALUES_SEPARATOR);
+
+        final String[] keys = StringUtils.isBlank(schemaTO.getEnumerationKeys())
+                ? new String[0]
+                : schemaTO.getEnumerationKeys().split(SyncopeConstants.ENUM_VALUES_SEPARATOR);
+
+        for (int i = 0; i < values.length; i++) {
+            res.put(values[i].trim(), keys.length > i ? keys[i].trim() : null);
+        }
+
+        return res;
+    }
+
+    private List<String> getEnumeratedValues(final PlainSchemaTO schemaTO) {
+        final List<String> res = new ArrayList<>();
+
+        final String[] values = StringUtils.isBlank(schemaTO.getEnumerationValues())
+                ? new String[0]
+                : schemaTO.getEnumerationValues().split(SyncopeConstants.ENUM_VALUES_SEPARATOR);
+
+        for (String value : values) {
+            res.add(value.trim());
+        }
+
+        return res;
+    }
+
+    @Override
+    public void onEvent(final IEvent<?> event) {
+        if ((event.getPayload() instanceof RoleAttrTemplatesChange)) {
+            final RoleAttrTemplatesChange update = (RoleAttrTemplatesChange) event.getPayload();
+            if (attrTemplates != null && update.getType() == AttrTemplatesPanel.Type.rPlainAttrTemplates) {
+                setSchemas();
+                setAttrs();
+                update.getTarget().add(this);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/panels/PoliciesPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/PoliciesPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/PoliciesPanel.java
new file mode 100644
index 0000000..4d66eda
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/PoliciesPanel.java
@@ -0,0 +1,343 @@
+/*
+ * 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.panels;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.PreferenceManager;
+import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
+import org.apache.syncope.client.console.commons.XMLRolesReader;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.pages.PolicyModalPage;
+import org.apache.syncope.client.console.rest.PolicyRestClient;
+import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractPolicyTO;
+import org.apache.syncope.common.lib.to.AccountPolicyTO;
+import org.apache.syncope.common.lib.to.PasswordPolicyTO;
+import org.apache.syncope.common.lib.to.SyncPolicyTO;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.DropDownChoice;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.request.http.WebResponse;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PoliciesPanel extends Panel {
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(PoliciesPanel.class);
+
+    private static final int MODAL_WIN_HEIGHT = 400;
+
+    private static final int MODAL_WIN_WIDTH = 1000;
+
+    private static final long serialVersionUID = -6804066913177804275L;
+
+    @SpringBean
+    private PolicyRestClient policyRestClient;
+
+    @SpringBean
+    protected XMLRolesReader xmlRolesReader;
+
+    @SpringBean
+    private PreferenceManager prefMan;
+
+    private final PageReference pageRef;
+
+    private final int paginatorRows = prefMan.getPaginatorRows(getWebRequest(), Constants.PREF_POLICY_PAGINATOR_ROWS);
+
+    protected boolean modalResult = false;
+
+    private final PolicyType policyType;
+
+    public PoliciesPanel(final String id, final PageReference pageRef, final PolicyType policyType) {
+        super(id);
+        this.pageRef = pageRef;
+        this.policyType = policyType;
+
+        // Modal window for editing user attributes
+        final ModalWindow mwindow = new ModalWindow("editModalWin");
+        mwindow.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        mwindow.setInitialHeight(MODAL_WIN_HEIGHT);
+        mwindow.setInitialWidth(MODAL_WIN_WIDTH);
+        mwindow.setCookieName("policy-modal");
+        add(mwindow);
+
+        // Container for user list
+        final WebMarkupContainer container = new WebMarkupContainer("container");
+        container.setOutputMarkupId(true);
+        add(container);
+
+        setWindowClosedCallback(mwindow, container);
+
+        final List<IColumn<AbstractPolicyTO, String>> columns = new ArrayList<>();
+
+        columns.add(new PropertyColumn<AbstractPolicyTO, String>(new ResourceModel("key"), "key", "key"));
+
+        columns.add(new PropertyColumn<AbstractPolicyTO, String>(
+                new ResourceModel("description"), "description", "description"));
+
+        columns.add(new AbstractColumn<AbstractPolicyTO, String>(new ResourceModel("type")) {
+
+            private static final long serialVersionUID = 8263694778917279290L;
+
+            @Override
+            public void populateItem(final Item<ICellPopulator<AbstractPolicyTO>> cellItem, final String componentId,
+                    final IModel<AbstractPolicyTO> model) {
+
+                cellItem.add(new Label(componentId, getString(model.getObject().getType().name())));
+            }
+        });
+
+        columns.add(new AbstractColumn<AbstractPolicyTO, String>(new ResourceModel("actions", "")) {
+
+            private static final long serialVersionUID = 2054811145491901166L;
+
+            @Override
+            public String getCssClass() {
+                return "action";
+            }
+
+            @Override
+            public void populateItem(final Item<ICellPopulator<AbstractPolicyTO>> cellItem, final String componentId,
+                    final IModel<AbstractPolicyTO> model) {
+
+                final AbstractPolicyTO policyTO = model.getObject();
+
+                final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, pageRef);
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+
+                        mwindow.setPageCreator(new ModalWindow.PageCreator() {
+
+                            private static final long serialVersionUID = -7834632442532690940L;
+
+                            @SuppressWarnings({ "unchecked", "rawtypes" })
+                            @Override
+                            public Page createPage() {
+                                return new PolicyModalPage(pageRef, mwindow, policyTO);
+                            }
+                        });
+
+                        mwindow.show(target);
+                    }
+                }, ActionLink.ActionType.EDIT, "Policies");
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        try {
+                            policyRestClient.delete(policyTO.getKey(), policyTO.getClass());
+                            info(getString(Constants.OPERATION_SUCCEEDED));
+                        } catch (SyncopeClientException e) {
+                            error(getString(Constants.OPERATION_ERROR));
+
+                            LOG.error("While deleting policy {}({})",
+                                    policyTO.getKey(), policyTO.getDescription(), e);
+                        }
+
+                        target.add(container);
+                        ((NotificationPanel) getPage().get(Constants.FEEDBACK)).refresh(target);
+                    }
+                }, ActionLink.ActionType.DELETE, "Policies");
+
+                cellItem.add(panel);
+            }
+        });
+
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        final AjaxFallbackDefaultDataTable table = new AjaxFallbackDefaultDataTable("datatable", columns,
+                new PolicyDataProvider(), paginatorRows);
+
+        container.add(table);
+
+        final AjaxLink<Void> createButton = new ClearIndicatingAjaxLink<Void>("createLink", pageRef) {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            protected void onClickInternal(final AjaxRequestTarget target) {
+                mwindow.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = -7834632442532690940L;
+
+                    @SuppressWarnings({ "unchecked", "rawtypes" })
+                    @Override
+                    public Page createPage() {
+                        return new PolicyModalPage(pageRef, mwindow, getPolicyTOInstance(policyType));
+                    }
+                });
+
+                mwindow.show(target);
+            }
+        };
+
+        add(createButton);
+
+        MetaDataRoleAuthorizationStrategy.authorize(
+                createButton, ENABLE, xmlRolesReader.getEntitlement("Policies", "create"));
+
+        @SuppressWarnings("rawtypes")
+        final Form paginatorForm = new Form("PaginatorForm");
+
+        @SuppressWarnings({ "unchecked", "rawtypes" })
+        final DropDownChoice rowsChooser = new DropDownChoice("rowsChooser", new PropertyModel(this, "paginatorRows"),
+                prefMan.getPaginatorChoices());
+
+        rowsChooser.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                prefMan.set(getWebRequest(), (WebResponse) getResponse(), Constants.PREF_POLICY_PAGINATOR_ROWS, String
+                        .valueOf(paginatorRows));
+                table.setItemsPerPage(paginatorRows);
+
+                target.add(container);
+            }
+        });
+
+        paginatorForm.add(rowsChooser);
+        add(paginatorForm);
+    }
+
+    private void setWindowClosedCallback(final ModalWindow window, final WebMarkupContainer container) {
+        window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
+
+            private static final long serialVersionUID = 8804221891699487139L;
+
+            @Override
+            public void onClose(final AjaxRequestTarget target) {
+                target.add(container);
+                BasePage configuration = ((BasePage) pageRef.getPage());
+                if (configuration.isModalResult()) {
+                    info(getString(Constants.OPERATION_SUCCEEDED));
+                    configuration.getFeedbackPanel().refresh(target);
+                    configuration.setModalResult(false);
+                }
+            }
+        });
+    }
+
+    private class PolicyDataProvider extends SortableDataProvider<AbstractPolicyTO, String> {
+
+        private static final long serialVersionUID = -6976327453925166730L;
+
+        private final SortableDataProviderComparator<AbstractPolicyTO> comparator;
+
+        public PolicyDataProvider() {
+            super();
+
+            //Default sorting
+            setSort("description", SortOrder.ASCENDING);
+
+            comparator = new SortableDataProviderComparator<AbstractPolicyTO>(this);
+        }
+
+        @Override
+        public long size() {
+            return policyRestClient.getPolicies(policyType, true).size();
+        }
+
+        @Override
+        public Iterator<AbstractPolicyTO> iterator(final long first, final long count) {
+            final List<AbstractPolicyTO> policies = policyRestClient.getPolicies(policyType, true);
+
+            Collections.sort(policies, comparator);
+
+            return policies.subList((int) first, (int) first + (int) count).iterator();
+        }
+
+        @Override
+        public IModel<AbstractPolicyTO> model(final AbstractPolicyTO object) {
+            return new CompoundPropertyModel<AbstractPolicyTO>(object);
+        }
+    }
+
+    private AbstractPolicyTO getPolicyTOInstance(final PolicyType policyType) {
+        AbstractPolicyTO policyTO;
+        switch (policyType) {
+            case GLOBAL_ACCOUNT:
+                policyTO = new AccountPolicyTO(true);
+                break;
+
+            case ACCOUNT:
+                policyTO = new AccountPolicyTO();
+                break;
+
+            case GLOBAL_PASSWORD:
+                policyTO = new PasswordPolicyTO(true);
+                break;
+
+            case PASSWORD:
+                policyTO = new PasswordPolicyTO();
+                break;
+
+            case GLOBAL_SYNC:
+                policyTO = new SyncPolicyTO(true);
+                break;
+
+            case SYNC:
+            default:
+                policyTO = new SyncPolicyTO();
+        }
+
+        return policyTO;
+    }
+}