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/05 17:01:08 UTC

[37/52] syncope git commit: [SYNCOPE-620] Console (JAR) in, now time for console-reference

http://git-wip-us.apache.org/repos/asf/syncope/blob/32707b3b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/ResultStatusModalPage.java
----------------------------------------------------------------------
diff --git a/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/ResultStatusModalPage.java b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/ResultStatusModalPage.java
new file mode 100644
index 0000000..4a3589c
--- /dev/null
+++ b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/ResultStatusModalPage.java
@@ -0,0 +1,426 @@
+/*
+ * 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 java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.ConnIdSpecialAttributeName;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.Mode;
+import org.apache.syncope.client.console.commons.status.Status;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.common.lib.to.AbstractSubjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.PropagationStatus;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.PropagationTaskExecStatus;
+import org.apache.wicket.Component;
+import org.apache.wicket.Page;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+/**
+ * Show user or role status after performing a successful operation.
+ */
+public class ResultStatusModalPage extends BaseModalPage {
+
+    private static final long serialVersionUID = 2646115294319713723L;
+
+    private static final String IMG_STATUSES = "statuses/";
+
+    @SpringBean(name = "anonymousUser")
+    private String anonymousUser;
+
+    private final AbstractSubjectTO subject;
+
+    private final Mode mode;
+
+    /**
+     * Status management utilities.
+     */
+    private final StatusUtils statusUtils;
+
+    public static class Builder implements Serializable {
+
+        private static final long serialVersionUID = 220361441802274899L;
+
+        private ModalWindow window;
+
+        private Mode mode;
+
+        private AbstractSubjectTO subject;
+
+        public Builder(final ModalWindow window, final AbstractSubjectTO attributable) {
+            this.window = window;
+            this.subject = attributable;
+        }
+
+        public ResultStatusModalPage.Builder mode(final Mode mode) {
+            this.mode = mode;
+            return this;
+        }
+
+        public ResultStatusModalPage build() {
+            return new ResultStatusModalPage(this);
+        }
+    }
+
+    private ResultStatusModalPage(final Builder builder) {
+        super();
+        this.subject = builder.subject;
+        statusUtils = new StatusUtils(this.userRestClient);
+        if (builder.mode == null) {
+            this.mode = Mode.ADMIN;
+        } else {
+            this.mode = builder.mode;
+        }
+
+        final BaseModalPage page = this;
+
+        final WebMarkupContainer container = new WebMarkupContainer("container");
+        container.setOutputMarkupId(true);
+        add(container);
+
+        final Fragment fragment = new Fragment("resultFrag", mode == Mode.SELF
+                ? "userSelfResultFrag"
+                : "propagationResultFrag", this);
+        fragment.setOutputMarkupId(true);
+        container.add(fragment);
+
+        if (mode == Mode.ADMIN) {
+            // add Syncope propagation status
+            PropagationStatus syncope = new PropagationStatus();
+            syncope.setResource("Syncope");
+            syncope.setStatus(PropagationTaskExecStatus.SUCCESS);
+
+            List<PropagationStatus> propagations = new ArrayList<PropagationStatus>();
+            propagations.add(syncope);
+            propagations.addAll(subject.getPropagationStatusTOs());
+
+            fragment.add(new Label("info",
+                    ((subject instanceof UserTO) && ((UserTO) subject).getUsername() != null)
+                            ? ((UserTO) subject).getUsername()
+                            : ((subject instanceof RoleTO) && ((RoleTO) subject).getName() != null)
+                                    ? ((RoleTO) subject).getName()
+                                    : String.valueOf(subject.getKey())));
+
+            final ListView<PropagationStatus> propRes = new ListView<PropagationStatus>("resources",
+                    propagations) {
+
+                        private static final long serialVersionUID = -1020475259727720708L;
+
+                        @Override
+                        protected void populateItem(final ListItem<PropagationStatus> item) {
+                            final PropagationStatus propTO = (PropagationStatus) item.getDefaultModelObject();
+
+                            final ListView attributes = getConnObjectView(propTO);
+
+                            final Fragment attrhead;
+                            if (attributes.getModelObject() == null || attributes.getModelObject().isEmpty()) {
+                                attrhead = new Fragment("attrhead", "emptyAttrHeadFrag", page);
+                            } else {
+                                attrhead = new Fragment("attrhead", "attrHeadFrag", page);
+                            }
+
+                            item.add(attrhead);
+                            item.add(attributes);
+
+                            attrhead.add(new Label("resource", propTO.getResource()));
+
+                            attrhead.add(new Label("propagation", propTO.getStatus() == null
+                                                    ? "UNDEFINED" : propTO.getStatus().toString()));
+
+                            final Image image;
+                            final String alt, title;
+                            final ModalWindow failureWindow = new ModalWindow("failureWindow");
+                            final AjaxLink<?> failureWindowLink = new AjaxLink<Void>("showFailureWindow") {
+
+                                private static final long serialVersionUID = -7978723352517770644L;
+
+                                @Override
+                                public void onClick(AjaxRequestTarget target) {
+                                    failureWindow.show(target);
+                                }
+                            };
+
+                            switch (propTO.getStatus()) {
+
+                                case SUCCESS:
+                                case SUBMITTED:
+                                case CREATED:
+                                    image = new Image("icon", IMG_STATUSES + Status.ACTIVE.toString()
+                                            + Constants.PNG_EXT);
+                                    alt = "success icon";
+                                    title = "success";
+                                    failureWindow.setVisible(false);
+                                    failureWindowLink.setEnabled(false);
+                                    break;
+
+                                default:
+                                    image = new Image("icon", IMG_STATUSES + Status.SUSPENDED.toString()
+                                            + Constants.PNG_EXT);
+                                    alt = "failure icon";
+                                    title = "failure";
+                            }
+
+                            image.add(new Behavior() {
+
+                                private static final long serialVersionUID = 1469628524240283489L;
+
+                                @Override
+                                public void onComponentTag(final Component component, final ComponentTag tag) {
+                                    tag.put("alt", alt);
+                                    tag.put("title", title);
+                                }
+                            });
+                            final FailureMessageModalPage executionFailureMessagePage;
+                            if (propTO.getFailureReason() == null) {
+                                executionFailureMessagePage =
+                                new FailureMessageModalPage(failureWindow.getContentId(), StringUtils.EMPTY);
+                            } else {
+                                executionFailureMessagePage =
+                                new FailureMessageModalPage(failureWindow.getContentId(), propTO.getFailureReason());
+                            }
+
+                            failureWindow.setPageCreator(new ModalWindow.PageCreator() {
+
+                                private static final long serialVersionUID = -7834632442532690940L;
+
+                                @Override
+                                public Page createPage() {
+                                    return executionFailureMessagePage;
+                                }
+                            });
+                            failureWindow.setCookieName("failureWindow");
+                            failureWindow.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+                            failureWindowLink.add(image);
+                            attrhead.add(failureWindowLink);
+                            attrhead.add(failureWindow);
+                        }
+                    };
+            fragment.add(propRes);
+        }
+
+        final AjaxLink<Void> close = new IndicatingAjaxLink<Void>("close") {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                builder.window.close(target);
+            }
+        };
+        container.add(close);
+
+        setOutputMarkupId(true);
+    }
+
+    /**
+     * Get remote attributes list view.
+     *
+     * @param propTO propagation TO.
+     * @return list view.
+     */
+    private ListView<String> getConnObjectView(final PropagationStatus propTO) {
+        final ConnObjectTO before = propTO.getBeforeObj();
+        final ConnObjectTO after = propTO.getAfterObj();
+
+        // sorted in reversed presentation order
+        final List<String> head = new ArrayList<String>();
+        if (subject instanceof UserTO) {
+            head.add(ConnIdSpecialAttributeName.PASSWORD);
+            head.add(ConnIdSpecialAttributeName.ENABLE);
+        }
+        head.add(ConnIdSpecialAttributeName.UID);
+        head.add(ConnIdSpecialAttributeName.NAME);
+
+        final Map<String, AttrTO> beforeAttrMap = before == null
+                ? Collections.<String, AttrTO>emptyMap()
+                : before.getPlainAttrMap();
+
+        final Map<String, AttrTO> afterAttrMap = after == null
+                ? Collections.<String, AttrTO>emptyMap()
+                : after.getPlainAttrMap();
+
+        final Set<String> attributes = new HashSet<String>();
+        attributes.addAll(beforeAttrMap.keySet());
+        attributes.addAll(afterAttrMap.keySet());
+
+        if (!(subject instanceof UserTO)) {
+            attributes.remove(ConnIdSpecialAttributeName.PASSWORD);
+            attributes.remove(ConnIdSpecialAttributeName.ENABLE);
+        }
+
+        final List<String> profile = new ArrayList<String>();
+        profile.addAll(attributes);
+        profile.removeAll(head);
+        Collections.sort(profile);
+
+        for (String attr : head) {
+            if (attributes.contains(attr)) {
+                profile.add(0, attr);
+            }
+        }
+
+        return new ListView<String>("attrs", profile) {
+
+            private static final long serialVersionUID = 4949588177564901031L;
+
+            @Override
+            protected void populateItem(final ListItem<String> item) {
+                String name = item.getModelObject();
+
+                final Fragment beforeValue;
+                final Fragment afterValue;
+                if (ConnIdSpecialAttributeName.ENABLE.equals(name)) {
+                    beforeValue = getStatusIcon("beforeValue", propTO.getResource(), before);
+                    afterValue = getStatusIcon("afterValue", propTO.getResource(), after);
+                } else {
+                    beforeValue = getLabelValue("beforeValue", name, beforeAttrMap);
+                    afterValue = getLabelValue("afterValue", name, afterAttrMap);
+                }
+
+                item.add(new Label("attrName", new ResourceModel(name, name)));
+
+                item.add(beforeValue);
+                item.add(afterValue);
+            }
+        };
+    }
+
+    /**
+     * Get fragment for attribute value (not remote status).
+     *
+     * @param id component id to be replaced with the fragment content.
+     * @param attrName remote attribute name
+     * @param attrMap remote attributes map.
+     * @return fragment.
+     */
+    private Fragment getLabelValue(final String id, final String attrName, final Map<String, AttrTO> attrMap) {
+        final String value;
+
+        final AttrTO attr = attrMap.get(attrName);
+
+        if (attr == null || attr.getValues() == null || attr.getValues().isEmpty()) {
+            value = "";
+        } else {
+            if (ConnIdSpecialAttributeName.PASSWORD.equals(attrName)) {
+                value = "********";
+            } else {
+                value = attr.getValues().size() > 1
+                        ? attr.getValues().toString()
+                        : attr.getValues().get(0);
+            }
+        }
+
+        Component label = new Label("value", value.length() > 50 ? value.substring(0, 50) + "..." : value).
+                add(new Behavior() {
+
+                    private static final long serialVersionUID = 1469628524240283489L;
+
+                    @Override
+                    public void onComponentTag(final Component component, final ComponentTag tag) {
+                        tag.put("title", value);
+                    }
+                });
+
+        final Fragment frag = new Fragment(id, "attrValueFrag", this);
+        frag.add(label);
+
+        return frag;
+    }
+
+    /**
+     * Get fragment for user status icon.
+     *
+     * @param id component id to be replaced with the fragment content
+     * @param resourceName resource name
+     * @param objectTO connector object TO
+     * @return fragment.
+     */
+    private Fragment getStatusIcon(final String id, final String resourceName, final ConnObjectTO objectTO) {
+        final Image image;
+        final String alt, title;
+        switch (statusUtils.getStatusBean(
+                subject, resourceName, objectTO, this.subject instanceof RoleTO).getStatus()) {
+
+            case ACTIVE:
+                image = new Image("status", IMG_STATUSES + Status.ACTIVE.toString()
+                        + Constants.PNG_EXT);
+                alt = "active icon";
+                title = "Enabled";
+                break;
+
+            case SUSPENDED:
+                image = new Image("status", IMG_STATUSES + Status.SUSPENDED.toString()
+                        + Constants.PNG_EXT);
+                alt = "inactive icon";
+                title = "Disabled";
+                break;
+
+            default:
+                image = null;
+                alt = null;
+                title = null;
+        }
+
+        final Fragment frag;
+        if (image == null) {
+            frag = new Fragment(id, "emptyFrag", this);
+        } else {
+            image.add(new Behavior() {
+
+                private static final long serialVersionUID = 1469628524240283489L;
+
+                @Override
+                public void onComponentTag(final Component component, final ComponentTag tag) {
+                    tag.put("alt", alt);
+                    tag.put("title", title);
+                    tag.put("width", "12px");
+                    tag.put("height", "12px");
+                }
+            });
+
+            frag = new Fragment(id, "remoteStatusFrag", this);
+            frag.add(image);
+        }
+
+        return frag;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/32707b3b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleModalPage.java
----------------------------------------------------------------------
diff --git a/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleModalPage.java b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleModalPage.java
new file mode 100644
index 0000000..3cb9148
--- /dev/null
+++ b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleModalPage.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.Mode;
+import org.apache.syncope.client.console.panels.RolePanel;
+import org.apache.syncope.common.lib.AttributableOperations;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.ResourceModel;
+
+/**
+ * Modal window with Role form.
+ */
+public class RoleModalPage extends BaseModalPage {
+
+    private static final long serialVersionUID = -1732493223434085205L;
+
+    protected final PageReference pageRef;
+
+    protected final ModalWindow window;
+
+    protected final Mode mode;
+
+    protected final boolean createFlag;
+
+    protected final RolePanel rolePanel;
+
+    protected RoleTO originalRoleTO;
+
+    public RoleModalPage(final PageReference pageRef, final ModalWindow window, final RoleTO roleTO) {
+        this(pageRef, window, roleTO, Mode.ADMIN);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public RoleModalPage(final PageReference pageRef, final ModalWindow window, final RoleTO roleTO, final Mode mode) {
+        super();
+
+        this.pageRef = pageRef;
+        this.window = window;
+        this.mode = mode;
+
+        this.createFlag = roleTO.getKey() == 0;
+        if (!createFlag) {
+            originalRoleTO = SerializationUtils.clone(roleTO);
+        }
+
+        final Form<RoleTO> form = new Form<RoleTO>("roleForm");
+        form.setMultiPart(true);
+
+        add(new Label("displayName", roleTO.getKey() == 0 ? "" : roleTO.getDisplayName()));
+
+        form.setModel(new CompoundPropertyModel<RoleTO>(roleTO));
+
+        this.rolePanel = new RolePanel.Builder("rolePanel").form(form).roleTO(roleTO).
+                roleModalPageMode(mode).pageRef(getPageReference()).build();
+        form.add(rolePanel);
+
+        final AjaxButton submit = new IndicatingAjaxButton(SUBMIT, new ResourceModel(SUBMIT)) {
+
+            private static final long serialVersionUID = -958724007591692537L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+                try {
+                    submitAction(target, form);
+
+                    if (pageRef.getPage() instanceof BasePage) {
+                        ((BasePage) pageRef.getPage()).setModalResult(true);
+                    }
+
+                    closeAction(target, form);
+                } catch (Exception e) {
+                    error(getString(Constants.ERROR) + ": " + e.getMessage());
+                    feedbackPanel.refresh(target);
+                }
+            }
+
+            @Override
+            protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+                feedbackPanel.refresh(target);
+            }
+        };
+        form.add(submit);
+        form.setDefaultButton(submit);
+
+        final AjaxButton cancel = new IndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL)) {
+
+            private static final long serialVersionUID = -958724007591692537L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+                closeAction(target, form);
+            }
+        };
+        cancel.setDefaultFormProcessing(false);
+        form.add(cancel);
+
+        MetaDataRoleAuthorizationStrategy.authorize(submit, ENABLE, xmlRolesReader.getEntitlement("Roles",
+                createFlag
+                        ? "create"
+                        : "update"));
+
+        add(form);
+    }
+
+    protected void submitAction(final AjaxRequestTarget target, final Form<?> form) {
+        final RoleTO roleTO = (RoleTO) form.getDefaultModelObject();
+        final List<String> entitlementList = new ArrayList<String>(rolePanel.getSelectedEntitlements());
+        roleTO.getEntitlements().clear();
+        roleTO.getEntitlements().addAll(entitlementList);
+
+        RoleTO result;
+        if (createFlag) {
+            result = roleRestClient.create(roleTO);
+        } else {
+            RoleMod roleMod = AttributableOperations.diff(roleTO, originalRoleTO);
+
+            // update role just if it is changed
+            if (roleMod.isEmpty()) {
+                result = roleTO;
+            } else {
+                result = roleRestClient.update(originalRoleTO.getETagValue(), roleMod);
+            }
+        }
+
+        setResponsePage(new ResultStatusModalPage.Builder(window, result).build());
+    }
+
+    protected void closeAction(final AjaxRequestTarget target, final Form<?> form) {
+        window.close(target);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/32707b3b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleSelectModalPage.java
----------------------------------------------------------------------
diff --git a/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleSelectModalPage.java b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleSelectModalPage.java
new file mode 100644
index 0000000..26b1aea
--- /dev/null
+++ b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleSelectModalPage.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import java.lang.reflect.Constructor;
+import javax.swing.tree.DefaultMutableTreeNode;
+import org.apache.syncope.client.console.commons.RoleTreeBuilder;
+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.RoleTO;
+import org.apache.wicket.Component;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.event.Broadcast;
+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.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class RoleSelectModalPage extends BaseModalPage {
+
+    private static final long serialVersionUID = 2106489458494696439L;
+
+    @SpringBean
+    private RoleTreeBuilder roleTreeBuilder;
+
+    private final NestedTree<DefaultMutableTreeNode> tree;
+
+    public RoleSelectModalPage(final PageReference pageRef, final ModalWindow window, final Class<?> payloadClass) {
+        super();
+
+        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, RoleSelectModalPage.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<>(roleTO.getDisplayName());
+                    }
+
+                    @Override
+                    protected void onClick(final AjaxRequestTarget target) {
+                        super.onClick(target);
+
+                        try {
+                            Constructor<?> constructor = payloadClass.getConstructor(Long.class);
+                            Object payload = constructor.newInstance(roleTO.getKey());
+
+                            send(pageRef.getPage(), Broadcast.BREADTH, payload);
+                        } catch (Exception e) {
+                            LOG.error("Could not send role select event", e);
+                        }
+
+                        window.close(target);
+                    }
+                };
+            }
+        };
+        tree.add(new WindowsTheme());
+        tree.setOutputMarkupId(true);
+
+        DefaultMutableTreeNodeExpansion.get().expandAll();
+
+        this.add(tree);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/32707b3b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleTemplateModalPage.java
----------------------------------------------------------------------
diff --git a/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleTemplateModalPage.java b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleTemplateModalPage.java
new file mode 100644
index 0000000..6639517
--- /dev/null
+++ b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/RoleTemplateModalPage.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import org.apache.syncope.client.console.commons.Mode;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.to.SyncTaskTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.form.Form;
+
+public class RoleTemplateModalPage extends RoleModalPage {
+
+    private static final long serialVersionUID = -3849135555203409845L;
+
+    private final SyncTaskTO syncTaskTO;
+
+    public RoleTemplateModalPage(final PageReference callerPageRef, final ModalWindow window,
+            final SyncTaskTO syncTaskTO) {
+
+        super(callerPageRef, window, syncTaskTO.getRoleTemplate() == null
+                ? new RoleTO()
+                : syncTaskTO.getRoleTemplate(), Mode.TEMPLATE);
+
+        this.syncTaskTO = syncTaskTO;
+    }
+
+    @Override
+    protected void submitAction(final AjaxRequestTarget target, final Form form) {
+        syncTaskTO.setRoleTemplate((RoleTO) form.getModelObject());
+        taskRestClient.updateSyncTask(syncTaskTO);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/32707b3b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/Roles.java
----------------------------------------------------------------------
diff --git a/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/Roles.java b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/Roles.java
new file mode 100644
index 0000000..8310792
--- /dev/null
+++ b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/Roles.java
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.AbstractSearchResultPanel;
+import org.apache.syncope.client.console.panels.RoleSearchPanel;
+import org.apache.syncope.client.console.panels.RoleSearchResultPanel;
+import org.apache.syncope.client.console.panels.RoleSummaryPanel;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxButton;
+import org.apache.syncope.client.console.wicket.markup.html.tree.TreeRolePanel;
+import org.apache.wicket.Session;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+/**
+ * Roles WebPage.
+ */
+public class Roles extends BasePage {
+
+    private static final long serialVersionUID = -2147758241610831969L;
+
+    private static final int WIN_HEIGHT = 500;
+
+    private static final int WIN_WIDTH = 800;
+
+    @SpringBean
+    private RoleRestClient restClient;
+
+    private final ModalWindow editRoleWin;
+
+    private final WebMarkupContainer roleTabsContainer;
+
+    public Roles(final PageParameters parameters) {
+        super(parameters);
+
+        roleTabsContainer = new WebMarkupContainer("roleTabsContainer");
+        roleTabsContainer.setOutputMarkupId(true);
+        add(roleTabsContainer);
+
+        editRoleWin = new ModalWindow("editRoleWin");
+        editRoleWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        editRoleWin.setInitialHeight(WIN_HEIGHT);
+        editRoleWin.setInitialWidth(WIN_WIDTH);
+        editRoleWin.setCookieName("edit-role-modal");
+        add(editRoleWin);
+
+        final TreeRolePanel treePanel = new TreeRolePanel("treePanel");
+        treePanel.setOutputMarkupId(true);
+        roleTabsContainer.add(treePanel);
+
+        final RoleSummaryPanel summaryPanel = new RoleSummaryPanel.Builder("summaryPanel")
+                .window(editRoleWin).callerPageRef(Roles.this.getPageReference()).build();
+        roleTabsContainer.add(summaryPanel);
+
+        editRoleWin.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
+
+            private static final long serialVersionUID = 8804221891699487139L;
+
+            @Override
+            public void onClose(final AjaxRequestTarget target) {
+                final RoleSummaryPanel summaryPanel = (RoleSummaryPanel) roleTabsContainer.get("summaryPanel");
+
+                final TreeNodeClickUpdate data = new TreeNodeClickUpdate(target,
+                        summaryPanel == null || summaryPanel.getSelectedNode() == null
+                        ? 0
+                        : summaryPanel.getSelectedNode().getKey());
+
+                send(getPage(), Broadcast.BREADTH, data);
+
+                if (modalResult) {
+                    getSession().info(getString(Constants.OPERATION_SUCCEEDED));
+                    feedbackPanel.refresh(target);
+                    modalResult = false;
+                }
+
+            }
+        });
+
+        final AbstractSearchResultPanel searchResult =
+                new RoleSearchResultPanel("searchResult", true, null, getPageReference(), restClient);
+        add(searchResult);
+
+        final Form searchForm = new Form("searchForm");
+        add(searchForm);
+
+        final RoleSearchPanel searchPanel = new RoleSearchPanel.Builder("searchPanel").build();
+        searchForm.add(searchPanel);
+
+        searchForm.add(new ClearIndicatingAjaxButton("search", new ResourceModel("search"), getPageReference()) {
+
+            private static final long serialVersionUID = -958724007591692537L;
+
+            @Override
+            protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
+                final String fiql = searchPanel.buildFIQL();
+                LOG.debug("Node condition {}", fiql);
+
+                doSearch(target, fiql, searchResult);
+
+                Session.get().getFeedbackMessages().clear();
+                searchPanel.getSearchFeedback().refresh(target);
+            }
+
+            @Override
+            protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+                searchPanel.getSearchFeedback().refresh(target);
+            }
+        });
+    }
+
+    private void doSearch(final AjaxRequestTarget target, final String fiql,
+            final AbstractSearchResultPanel resultsetPanel) {
+
+        if (fiql == null) {
+            error(getString(Constants.SEARCH_ERROR));
+            return;
+        }
+
+        resultsetPanel.search(fiql, target);
+    }
+
+    @Override
+    public void onEvent(final IEvent<?> event) {
+        super.onEvent(event);
+
+        if (event.getPayload() instanceof TreeNodeClickUpdate) {
+            final TreeNodeClickUpdate update = (TreeNodeClickUpdate) event.getPayload();
+
+            final RoleSummaryPanel summaryPanel = new RoleSummaryPanel.Builder("summaryPanel")
+                    .window(editRoleWin).callerPageRef(Roles.this.getPageReference())
+                    .selectedNodeId(update.getSelectedNodeId()).build();
+
+            roleTabsContainer.addOrReplace(summaryPanel);
+            update.getTarget().add(roleTabsContainer);
+        }
+    }
+
+    public static class TreeNodeClickUpdate {
+
+        private final AjaxRequestTarget target;
+
+        private Long selectedNodeId;
+
+        public TreeNodeClickUpdate(final AjaxRequestTarget target, final Long selectedNodeId) {
+            this.target = target;
+            this.selectedNodeId = selectedNodeId;
+        }
+
+        public AjaxRequestTarget getTarget() {
+            return target;
+        }
+
+        public Long getSelectedNodeId() {
+            return selectedNodeId;
+        }
+
+        public void setSelectedNodeId(final Long selectedNodeId) {
+            this.selectedNodeId = selectedNodeId;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/32707b3b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/SchedTaskModalPage.java
----------------------------------------------------------------------
diff --git a/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/SchedTaskModalPage.java b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/SchedTaskModalPage.java
new file mode 100644
index 0000000..6222717
--- /dev/null
+++ b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/SchedTaskModalPage.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import java.util.List;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.model.PropertyModel;
+
+/**
+ * Modal window with Task form (to stop and start execution).
+ */
+public class SchedTaskModalPage extends AbstractSchedTaskModalPage {
+
+    private static final long serialVersionUID = -2501860242590060867L;
+
+    public SchedTaskModalPage(final ModalWindow window, final SchedTaskTO taskTO, final PageReference callerPageRef) {
+
+        super(window, taskTO, callerPageRef);
+
+        final IModel<List<String>> classNames = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<String> load() {
+                return taskRestClient.getJobClasses();
+            }
+        };
+
+        final AjaxDropDownChoicePanel<String> className = new AjaxDropDownChoicePanel<String>("jobClassName",
+                getString("class"), new PropertyModel<String>(taskTO, "jobClassName"));
+        className.setChoices(classNames.getObject());
+        className.addRequiredLabel();
+        className.setEnabled(taskTO.getKey() == 0);
+        className.setStyleSheet("ui-widget-content ui-corner-all long_dynamicsize");
+        profile.add(className);
+    }
+
+    @Override
+    public void submitAction(final SchedTaskTO taskTO) {
+        if (taskTO.getKey() > 0) {
+            taskRestClient.updateSchedTask(taskTO);
+        } else {
+            taskRestClient.createSchedTask(taskTO);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/32707b3b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/Schema.java
----------------------------------------------------------------------
diff --git a/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/Schema.java b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/Schema.java
new file mode 100644
index 0000000..8852862
--- /dev/null
+++ b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/Schema.java
@@ -0,0 +1,467 @@
+/*
+ * 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 java.lang.reflect.Field;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.PreferenceManager;
+import org.apache.syncope.client.console.commons.SchemaModalPageFactory;
+import org.apache.syncope.client.console.commons.SelectChoiceRenderer;
+import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
+import org.apache.syncope.client.console.panels.JQueryUITabbedPanel;
+import org.apache.syncope.client.console.rest.SchemaRestClient;
+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.ActionLink.ActionType;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.wicket.AttributeModifier;
+import org.apache.wicket.Page;
+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.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+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.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ * Schema WebPage.
+ */
+@SuppressWarnings({ "unchecked", "rawtypes" })
+public class Schema extends BasePage {
+
+    private static final long serialVersionUID = 8091922398776299403L;
+
+    private static final Map<SchemaType, List<String>> COL_NAMES = new HashMap<SchemaType, List<String>>() {
+
+        private static final long serialVersionUID = 3109256773218160485L;
+
+        {
+            put(SchemaType.PLAIN, Arrays.asList(new String[] { "name", "type",
+                "mandatoryCondition", "uniqueConstraint", "multivalue", "readonly" }));
+            put(SchemaType.DERIVED, Arrays.asList(new String[] { "name", "expression" }));
+            put(SchemaType.VIRTUAL, Arrays.asList(new String[] { "name", "readonly" }));
+        }
+    };
+
+    private static final Map<Map.Entry<AttributableType, SchemaType>, String> PAGINATOR_ROWS_KEYS =
+            new HashMap<Map.Entry<AttributableType, SchemaType>, String>() {
+
+                private static final long serialVersionUID = 3109256773218160485L;
+
+                {
+                    put(new SimpleEntry<>(AttributableType.CONFIGURATION, SchemaType.PLAIN),
+                            Constants.PREF_CONF_SCHEMA_PAGINATOR_ROWS);
+                    put(new SimpleEntry<>(AttributableType.USER, SchemaType.PLAIN),
+                            Constants.PREF_USER_SCHEMA_PAGINATOR_ROWS);
+                    put(new SimpleEntry<>(AttributableType.USER, SchemaType.DERIVED),
+                            Constants.PREF_USER_DER_SCHEMA_PAGINATOR_ROWS);
+                    put(new SimpleEntry<>(AttributableType.USER, SchemaType.VIRTUAL),
+                            Constants.PREF_USER_VIR_SCHEMA_PAGINATOR_ROWS);
+                    put(new SimpleEntry<>(AttributableType.MEMBERSHIP, SchemaType.PLAIN),
+                            Constants.PREF_MEMBERSHIP_SCHEMA_PAGINATOR_ROWS);
+                    put(new SimpleEntry<>(AttributableType.MEMBERSHIP, SchemaType.DERIVED),
+                            Constants.PREF_MEMBERSHIP_DER_SCHEMA_PAGINATOR_ROWS);
+                    put(new SimpleEntry<>(AttributableType.MEMBERSHIP, SchemaType.VIRTUAL),
+                            Constants.PREF_MEMBERSHIP_VIR_SCHEMA_PAGINATOR_ROWS);
+                    put(new SimpleEntry<>(AttributableType.ROLE, SchemaType.PLAIN),
+                            Constants.PREF_ROLE_SCHEMA_PAGINATOR_ROWS);
+                    put(new SimpleEntry<>(AttributableType.ROLE, SchemaType.DERIVED),
+                            Constants.PREF_ROLE_DER_SCHEMA_PAGINATOR_ROWS);
+                    put(new SimpleEntry<>(AttributableType.ROLE, SchemaType.VIRTUAL),
+                            Constants.PREF_ROLE_VIR_SCHEMA_PAGINATOR_ROWS);
+                }
+            };
+
+    private static final int WIN_WIDTH = 600;
+
+    private static final int WIN_HEIGHT = 200;
+
+    private static final int PLAIN_WIN_HEIGHT = 500;
+
+    @SpringBean
+    private SchemaRestClient restClient;
+
+    @SpringBean
+    private PreferenceManager prefMan;
+
+    private final String allowedCreateRoles = xmlRolesReader.getEntitlement("Schema", "create");
+
+    private final String allowedReadRoles = xmlRolesReader.getEntitlement("Schema", "read");
+
+    private final String allowedDeleteRoles = xmlRolesReader.getEntitlement("Schema", "delete");
+
+    public Schema() {
+        super();
+
+        for (final AttributableType attrType : AttributableType.values()) {
+            final String attrTypeAsString = attrType.name().toLowerCase();
+
+            List<ITab> tabs = new ArrayList<ITab>();
+
+            for (final SchemaType schemaType : SchemaType.values()) {
+                if (attrType != AttributableType.CONFIGURATION || schemaType == SchemaType.PLAIN) {
+                    final String schemaTypeAsString = schemaType.name().toLowerCase();
+
+                    tabs.add(new AbstractTab(new Model<String>(getString(schemaTypeAsString))) {
+
+                        private static final long serialVersionUID = -5861786415855103549L;
+
+                        @Override
+                        public WebMarkupContainer getPanel(final String panelId) {
+                            return new SchemaTypePanel(panelId, attrType, schemaType);
+                        }
+                    });
+                }
+            }
+
+            add(new JQueryUITabbedPanel(attrTypeAsString + "Tabs", tabs));
+        }
+    }
+
+    private <T extends AbstractSchemaModalPage> List<IColumn> getColumns(
+            final WebMarkupContainer webContainer, final ModalWindow modalWindow,
+            final AttributableType attributableType, final SchemaType schemaType,
+            final Collection<String> fields) {
+
+        List<IColumn> columns = new ArrayList<IColumn>();
+
+        for (final String field : fields) {
+            final Field clazzField = ReflectionUtils.findField(schemaType.getToClass(), field);
+
+            if (clazzField != null) {
+                if (clazzField.getType().equals(Boolean.class) || clazzField.getType().equals(boolean.class)) {
+                    columns.add(new AbstractColumn<AbstractSchemaTO, String>(new ResourceModel(field)) {
+
+                        private static final long serialVersionUID = 8263694778917279290L;
+
+                        @Override
+                        public void populateItem(final Item<ICellPopulator<AbstractSchemaTO>> item,
+                                final String componentId, final IModel<AbstractSchemaTO> model) {
+
+                            BeanWrapper bwi = new BeanWrapperImpl(model.getObject());
+                            Object obj = bwi.getPropertyValue(field);
+
+                            item.add(new Label(componentId, ""));
+                            item.add(new AttributeModifier("class", new Model<String>(obj.toString())));
+                        }
+
+                        @Override
+                        public String getCssClass() {
+                            return "small_fixedsize";
+                        }
+                    });
+                } else {
+                    IColumn column = new PropertyColumn(new ResourceModel(field), field, field) {
+
+                        private static final long serialVersionUID = 3282547854226892169L;
+
+                        @Override
+                        public String getCssClass() {
+                            String css = super.getCssClass();
+                            if ("name".equals(field)) {
+                                css = StringUtils.isBlank(css)
+                                        ? "medium_fixedsize"
+                                        : css + " medium_fixedsize";
+                            }
+                            return css;
+                        }
+                    };
+                    columns.add(column);
+                }
+            }
+        }
+
+        columns.add(new AbstractColumn<AbstractSchemaTO, String>(new ResourceModel("actions", "")) {
+
+            private static final long serialVersionUID = 2054811145491901166L;
+
+            @Override
+            public String getCssClass() {
+                return "action";
+            }
+
+            @Override
+            public void populateItem(final Item<ICellPopulator<AbstractSchemaTO>> item, final String componentId,
+                    final IModel<AbstractSchemaTO> model) {
+
+                final AbstractSchemaTO schemaTO = model.getObject();
+
+                final ActionLinksPanel panel = new ActionLinksPanel(componentId, model, getPageReference());
+
+                panel.addWithRoles(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        modalWindow.setPageCreator(new ModalWindow.PageCreator() {
+
+                            private static final long serialVersionUID = -7834632442532690940L;
+
+                            @Override
+                            public Page createPage() {
+                                AbstractSchemaModalPage page = SchemaModalPageFactory.getSchemaModalPage(
+                                        attributableType, schemaType);
+
+                                page.setSchemaModalPage(Schema.this.getPageReference(), modalWindow, schemaTO, false);
+
+                                return page;
+                            }
+                        });
+
+                        modalWindow.show(target);
+                    }
+                }, ActionType.EDIT, allowedReadRoles);
+
+                panel.addWithRoles(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+
+                        switch (schemaType) {
+                            case DERIVED:
+                                restClient.deleteDerSchema(attributableType, schemaTO.getKey());
+                                break;
+
+                            case VIRTUAL:
+                                restClient.deleteVirSchema(attributableType, schemaTO.getKey());
+                                break;
+
+                            default:
+                                restClient.deleteSchema(attributableType, schemaTO.getKey());
+                                break;
+                        }
+
+                        info(getString(Constants.OPERATION_SUCCEEDED));
+                        feedbackPanel.refresh(target);
+
+                        target.add(webContainer);
+                    }
+                }, ActionType.DELETE, allowedDeleteRoles);
+
+                item.add(panel);
+            }
+        });
+
+        return columns;
+    }
+
+    private Form<Void> getPaginatorForm(final WebMarkupContainer webContainer,
+            final AjaxFallbackDefaultDataTable dataTable,
+            final String formname, final SchemaTypePanel schemaTypePanel, final String rowsPerPagePrefName) {
+
+        Form<Void> form = new Form<Void>(formname);
+
+        final DropDownChoice<Integer> rowChooser = new DropDownChoice<Integer>("rowsChooser",
+                new PropertyModel<Integer>(schemaTypePanel, "pageRows"), prefMan.getPaginatorChoices(),
+                new SelectChoiceRenderer<Integer>());
+
+        rowChooser.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                prefMan.set(getRequest(), getResponse(), rowsPerPagePrefName, rowChooser.getInput());
+                dataTable.setItemsPerPage(rowChooser.getModelObject());
+
+                target.add(webContainer);
+            }
+        });
+
+        form.add(rowChooser);
+
+        return form;
+    }
+
+    private <T extends AbstractSchemaModalPage> AjaxLink<Void> getCreateSchemaLink(final ModalWindow modalWindow,
+            final AttributableType attrType, final SchemaType schemaType, final String winLinkName) {
+
+        AjaxLink<Void> link = new ClearIndicatingAjaxLink<Void>(winLinkName, getPageReference()) {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            protected void onClickInternal(final AjaxRequestTarget target) {
+                modalWindow.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = -7834632442532690940L;
+
+                    @Override
+                    public Page createPage() {
+                        T page = SchemaModalPageFactory.getSchemaModalPage(attrType, schemaType);
+                        page.setSchemaModalPage(Schema.this.getPageReference(), modalWindow, null, true);
+
+                        return page;
+                    }
+                });
+
+                modalWindow.show(target);
+            }
+        };
+
+        MetaDataRoleAuthorizationStrategy.authorize(link, ENABLE, allowedCreateRoles);
+
+        return link;
+
+    }
+
+    private class SchemaProvider extends SortableDataProvider<AbstractSchemaTO, String> {
+
+        private static final long serialVersionUID = -185944053385660794L;
+
+        private final SortableDataProviderComparator<AbstractSchemaTO> comparator;
+
+        private final AttributableType attrType;
+
+        private final SchemaType schemaType;
+
+        public SchemaProvider(final AttributableType attrType, final SchemaType schemaType) {
+            super();
+
+            this.attrType = attrType;
+            this.schemaType = schemaType;
+
+            // Default sorting
+            setSort("name", SortOrder.ASCENDING);
+
+            comparator = new SortableDataProviderComparator<AbstractSchemaTO>(this);
+        }
+
+        @Override
+        public Iterator<AbstractSchemaTO> iterator(final long first, final long count) {
+            @SuppressWarnings("unchecked")
+            List<AbstractSchemaTO> list =
+                    (List<AbstractSchemaTO>) restClient.getSchemas(this.attrType, this.schemaType);
+
+            Collections.sort(list, comparator);
+
+            return list.subList((int) first, (int) first + (int) count).iterator();
+        }
+
+        @Override
+        public long size() {
+            return restClient.getSchemas(this.attrType, this.schemaType).size();
+        }
+
+        @Override
+        public IModel<AbstractSchemaTO> model(final AbstractSchemaTO object) {
+            return new CompoundPropertyModel<AbstractSchemaTO>(object);
+        }
+    }
+
+    private class SchemaTypePanel extends Panel {
+
+        private static final long serialVersionUID = 2854050613688773575L;
+
+        private int pageRows;
+
+        private final AttributableType attrType;
+
+        private final SchemaType schemaType;
+
+        public SchemaTypePanel(final String id, final AttributableType attrType, final SchemaType schemaType) {
+            super(id);
+
+            this.attrType = attrType;
+            this.schemaType = schemaType;
+
+            setup();
+        }
+
+        private void setup() {
+            ModalWindow editSchemaWin = new ModalWindow("editSchemaWin");
+            editSchemaWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+            editSchemaWin.setInitialWidth(WIN_WIDTH);
+            if (schemaType == SchemaType.PLAIN) {
+                editSchemaWin.setInitialHeight(PLAIN_WIN_HEIGHT);
+            } else {
+                editSchemaWin.setInitialHeight(WIN_HEIGHT);
+            }
+            editSchemaWin.setCookieName("editSchemaWin");
+            editSchemaWin.setMarkupId("editSchemaWin");
+            add(editSchemaWin);
+
+            WebMarkupContainer schemaWrapContainer = new WebMarkupContainer("schemaWrapContainer");
+            schemaWrapContainer.setOutputMarkupId(true);
+            if (schemaType != SchemaType.VIRTUAL) {
+                schemaWrapContainer.add(new AttributeModifier("style", "width:auto;"));
+            }
+            add(schemaWrapContainer);
+
+            WebMarkupContainer schemaContainer = new WebMarkupContainer("schemaContainer");
+            schemaContainer.setOutputMarkupId(true);
+            schemaWrapContainer.add(schemaContainer);
+            setWindowClosedCallback(editSchemaWin, schemaContainer);
+
+            final String paginatorRowsKey = PAGINATOR_ROWS_KEYS.get(
+                    new SimpleEntry<AttributableType, SchemaType>(attrType, schemaType));
+            pageRows = prefMan.getPaginatorRows(getRequest(), paginatorRowsKey);
+
+            List<IColumn> tableCols = getColumns(schemaContainer, editSchemaWin, attrType,
+                    schemaType, COL_NAMES.get(schemaType));
+            final AjaxFallbackDefaultDataTable table = new AjaxFallbackDefaultDataTable("datatable", tableCols,
+                    new SchemaProvider(attrType, schemaType), pageRows);
+            table.setOutputMarkupId(true);
+            schemaContainer.add(table);
+
+            schemaWrapContainer.add(getPaginatorForm(schemaContainer, table, "paginatorForm", this, paginatorRowsKey));
+
+            add(getCreateSchemaLink(editSchemaWin, attrType, schemaType, "createSchemaLink"));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/32707b3b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/SecurityQuestionModalPage.java
----------------------------------------------------------------------
diff --git a/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/SecurityQuestionModalPage.java b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/SecurityQuestionModalPage.java
new file mode 100644
index 0000000..12bfc2b
--- /dev/null
+++ b/syncope620/client/console/src/main/java/org/apache/syncope/client/console/pages/SecurityQuestionModalPage.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.rest.SecurityQuestionRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.SecurityQuestionTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+class SecurityQuestionModalPage extends BaseModalPage {
+
+    private static final long serialVersionUID = -6709838862698327502L;
+
+    @SpringBean
+    private SecurityQuestionRestClient restClient;
+
+    public SecurityQuestionModalPage(final PageReference pageRef, final ModalWindow window,
+            final SecurityQuestionTO securityQuestionTO, final boolean createFlag) {
+
+        final Form<SecurityQuestionTO> form =
+                new Form<SecurityQuestionTO>(FORM, new CompoundPropertyModel<SecurityQuestionTO>(securityQuestionTO));
+
+        final AjaxTextFieldPanel contentFieldPanel =
+                new AjaxTextFieldPanel("content", "content", new PropertyModel<String>(securityQuestionTO, "content"));
+        contentFieldPanel.setRequired(true);
+        form.add(contentFieldPanel);
+
+        AjaxButton submit = new IndicatingAjaxButton(APPLY, new Model<String>(getString(SUBMIT))) {
+
+            private static final long serialVersionUID = -958724007591692537L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+                try {
+                    if (createFlag) {
+                        restClient.create(securityQuestionTO);
+                    } else {
+                        restClient.update(securityQuestionTO);
+                    }
+                    info(getString(Constants.OPERATION_SUCCEEDED));
+
+                    Configuration callerPage = (Configuration) pageRef.getPage();
+                    callerPage.setModalResult(true);
+
+                    window.close(target);
+                } catch (SyncopeClientException scee) {
+                    error(getString(Constants.ERROR) + ": " + scee.getMessage());
+                    feedbackPanel.refresh(target);
+                }
+            }
+
+            @Override
+            protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+                feedbackPanel.refresh(target);
+            }
+        };
+
+        final AjaxButton cancel = new IndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL)) {
+
+            private static final long serialVersionUID = -958724007591692537L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+                window.close(target);
+            }
+        };
+
+        cancel.setDefaultFormProcessing(false);
+
+        String allowedRoles = createFlag
+                ? xmlRolesReader.getEntitlement("SecurityQuestion", "create")
+                : xmlRolesReader.getEntitlement("SecurityQuestion", "update");
+        MetaDataRoleAuthorizationStrategy.authorize(submit, ENABLE, allowedRoles);
+
+        form.add(submit);
+        form.setDefaultButton(submit);
+
+        form.add(cancel);
+
+        add(form);
+    }
+}