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/08/13 12:40:02 UTC

[2/5] syncope git commit: [SYNCOPE-156] providing ListView table view + Provision wizard functionalities

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
index 5ec882c..4fc5a86 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java
@@ -39,7 +39,7 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.cxf.jaxrs.client.WebClient;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.pages.BasePage;
-import org.apache.syncope.client.console.panels.ResourceModal.ResourceCreateEvent;
+import org.apache.syncope.client.console.panels.AbstractResourceModal.CreateEvent;
 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.to.ConnInstanceTO;
@@ -49,6 +49,7 @@ import org.apache.syncope.common.rest.api.service.SyncopeService;
 import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.IAjaxIndicatorAware;
 import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.event.IEvent;
 import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
@@ -57,9 +58,7 @@ import org.apache.wicket.markup.head.OnDomReadyHeaderItem;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
-import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.LoadableDetachableModel;
-import org.apache.wicket.model.Model;
 import org.apache.wicket.protocol.ws.api.WebSocketBehavior;
 import org.apache.wicket.protocol.ws.api.WebSocketRequestHandler;
 import org.apache.wicket.protocol.ws.api.message.TextMessage;
@@ -69,7 +68,9 @@ public class Topology extends BasePage {
 
     private static final long serialVersionUID = -1100228004207271272L;
 
-    private static final String CONNECTOR_SERVER_LOCATION_PREFIX = "connid://";
+    public static final String CONNECTOR_SERVER_LOCATION_PREFIX = "connid://";
+
+    public static final String ROOT_NAME = "Syncope";
 
     private final int origX = 3100;
 
@@ -81,6 +82,10 @@ public class Topology extends BasePage {
 
     private final ModalWindow modal;
 
+    private final WebMarkupContainer newlyCreatedContainer;
+
+    private final ListView<TopologyNode> newlyCreated;
+
     private final LoadableDetachableModel<List<ResourceTO>> resModel = new LoadableDetachableModel<List<ResourceTO>>() {
 
         private static final long serialVersionUID = 5275935387613157431L;
@@ -92,45 +97,51 @@ public class Topology extends BasePage {
         }
     };
 
-    private final LoadableDetachableModel<Pair<List<ConnInstanceTO>, List<ConnInstanceTO>>> connModel =
-            new LoadableDetachableModel<Pair<List<ConnInstanceTO>, List<ConnInstanceTO>>>() {
+    private final LoadableDetachableModel<Map<String, List<ConnInstanceTO>>> connModel
+            = new LoadableDetachableModel<Map<String, List<ConnInstanceTO>>>() {
 
-        private static final long serialVersionUID = 5275935387613157432L;
+                private static final long serialVersionUID = 5275935387613157432L;
 
-        @Override
-        protected Pair<List<ConnInstanceTO>, List<ConnInstanceTO>> load() {
-            final List<ConnInstanceTO> level1 = new ArrayList<>();
-            final List<ConnInstanceTO> level2 = new ArrayList<>();
-
-            for (ConnInstanceTO conn : connectorRestClient.getAllConnectors()) {
-                if (conn.getLocation().startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) {
-                    level2.add(conn);
-                } else {
-                    level1.add(conn);
+                @Override
+                protected Map<String, List<ConnInstanceTO>> load() {
+                    final Map<String, List<ConnInstanceTO>> res = new HashMap<>();
+
+                    for (ConnInstanceTO conn : connectorRestClient.getAllConnectors()) {
+                        final List<ConnInstanceTO> conns;
+                        if (res.containsKey(conn.getLocation())) {
+                            conns = res.get(conn.getLocation());
+                        } else {
+                            conns = new ArrayList<>();
+                            res.put(conn.getLocation(), conns);
+                        }
+                        conns.add(conn);
+                    }
+
+                    return res;
                 }
-            }
+            };
 
-            return Pair.of(level1, level2);
-        }
-    };
+    private final LoadableDetachableModel<Pair<List<URI>, List<URI>>> csModel
+            = new LoadableDetachableModel<Pair<List<URI>, List<URI>>>() {
 
-    private final LoadableDetachableModel<List<URI>> csModel = new LoadableDetachableModel<List<URI>>() {
+                private static final long serialVersionUID = 5275935387613157433L;
 
-        private static final long serialVersionUID = 5275935387613157433L;
+                @Override
+                protected Pair<List<URI>, List<URI>> load() {
+                    final List<URI> connectorServers = new ArrayList<>();
+                    final List<URI> filePaths = new ArrayList<>();
 
-        @Override
-        protected List<URI> load() {
-            final List<URI> locations = new ArrayList<>();
+                    for (String location : SyncopeConsoleSession.get().getSyncopeTO().getConnIdLocations()) {
+                        if (location.startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) {
+                            connectorServers.add(URI.create(location));
+                        } else {
+                            filePaths.add(URI.create(location));
+                        }
+                    }
 
-            for (String location : SyncopeConsoleSession.get().getSyncopeTO().getConnIdLocations()) {
-                if (location.startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) {
-                    locations.add(URI.create(location));
+                    return Pair.of(connectorServers, filePaths);
                 }
-            }
-
-            return locations;
-        }
-    };
+            };
 
     private enum SupportedOperation {
 
@@ -203,32 +214,33 @@ public class Topology extends BasePage {
         // -----------------------------------------
         // Add Zoom panel
         // -----------------------------------------
-        final ActionLinksPanel zoomActionPanel = new ActionLinksPanel("zoom", new Model<String>(), getPageReference());
-        add(zoomActionPanel);
+        final ActionLinksPanel.Builder<Serializable> zoomActionPanel = ActionLinksPanel.builder(getPageReference());
 
-        zoomActionPanel.add(new ActionLink() {
+        zoomActionPanel.add(new ActionLink<Serializable>() {
 
             private static final long serialVersionUID = -3722207913631435501L;
 
             @Override
-            public void onClick(final AjaxRequestTarget target) {
+            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
                 target.appendJavaScript("zoomIn($('#drawing')[0]);");
             }
-        }, ActionLink.ActionType.ZOOM_IN, Entitlement.RESOURCE_LIST).add(new ActionLink() {
+        }, ActionLink.ActionType.ZOOM_IN, Entitlement.RESOURCE_LIST).add(new ActionLink<Serializable>() {
 
             private static final long serialVersionUID = -3722207913631435501L;
 
             @Override
-            public void onClick(final AjaxRequestTarget target) {
+            public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
                 target.appendJavaScript("zoomOut($('#drawing')[0]);");
             }
         }, ActionLink.ActionType.ZOOM_OUT, Entitlement.RESOURCE_LIST);
+
+        add(zoomActionPanel.build("zoom"));
         // -----------------------------------------
 
         // -----------------------------------------
         // Add Syncope (root topologynode)
         // -----------------------------------------
-        final TopologyNode syncopeTopologyNode = new TopologyNode("Syncope", "Syncope", TopologyNode.Kind.SYNCOPE);
+        final TopologyNode syncopeTopologyNode = new TopologyNode(ROOT_NAME, ROOT_NAME, TopologyNode.Kind.SYNCOPE);
         syncopeTopologyNode.setX(origX);
         syncopeTopologyNode.setY(origY);
 
@@ -250,11 +262,11 @@ public class Topology extends BasePage {
         // -----------------------------------------
         // Add Connector Servers
         // -----------------------------------------
-        final ListView<URI> connectorServers = new ListView<URI>("connectorServers", csModel) {
+        final ListView<URI> connectorServers = new ListView<URI>("connectorServers", csModel.getObject().getLeft()) {
 
             private static final long serialVersionUID = 6978621871488360380L;
 
-            private final int size = csModel.getObject().size() + 1;
+            private final int size = csModel.getObject().getLeft().size() + 1;
 
             @Override
             protected void populateItem(final ListItem<URI> item) {
@@ -287,102 +299,114 @@ public class Topology extends BasePage {
         // -----------------------------------------
 
         // -----------------------------------------
-        // Add Connector Intances (first level)
+        // Add File Paths
         // -----------------------------------------
-        final ListView<ConnInstanceTO> conn1 = new ListView<ConnInstanceTO>("conn1", connModel.getObject().getLeft()) {
+        final ListView<URI> filePaths = new ListView<URI>("filePaths", csModel.getObject().getRight()) {
 
-            private static final long serialVersionUID = 6978621871488360381L;
+            private static final long serialVersionUID = 6978621871488360380L;
 
-            private final int size = connModel.getObject().getLeft().size() + 1;
+            private final int size = csModel.getObject().getRight().size() + 1;
 
             @Override
-            protected void populateItem(final ListItem<ConnInstanceTO> item) {
-                int kx = size >= 6 ? 800 : (130 * size);
+            protected void populateItem(final ListItem<URI> item) {
+                int kx = size >= 4 ? 800 : (200 * size);
 
                 int x = (int) Math.round(origX + kx * Math.cos(Math.PI * (item.getIndex() + 1) / size));
                 int y = (int) Math.round(origY + 100 * Math.sin(Math.PI * (item.getIndex() + 1) / size));
 
-                final ConnInstanceTO conn = item.getModelObject();
-                final TopologyNode topologynode = new TopologyNode(
-                        Long.valueOf(conn.getKey()), conn.getDisplayName(), TopologyNode.Kind.CONNECTOR);
-                topologynode.setConnectinDisplayName(conn.getBundleName());
+                final URI location = item.getModelObject();
+                final String url = location.toASCIIString();
+
+                final TopologyNode topologynode = new TopologyNode(url, url, TopologyNode.Kind.FS_PATH);
+
+                topologynode.setHost(location.getHost());
+                topologynode.setPort(location.getPort());
                 topologynode.setX(x);
                 topologynode.setY(y);
 
-                connectors.put(Long.class.cast(topologynode.getKey()), topologynode);
-
-                item.add(topologyNodePanel("conn", topologynode));
+                servers.put(String.class.cast(topologynode.getKey()), topologynode);
 
-                if (conn.getLocation().startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) {
-                    final Map<Serializable, TopologyNode> remoteConnections;
+                item.add(topologyNodePanel("fp", topologynode));
 
-                    if (connections.containsKey(conn.getLocation())) {
-                        remoteConnections = connections.get(conn.getLocation());
-                    } else {
-                        remoteConnections = new HashMap<>();
-                        connections.put(conn.getLocation(), remoteConnections);
-                    }
-                    remoteConnections.put(conn.getKey(), topologynode);
-                } else {
-                    syncopeConnections.put(conn.getKey(), topologynode);
-                }
+                syncopeConnections.put(url, topologynode);
+                connections.put(url, new HashMap<Serializable, TopologyNode>());
             }
         };
 
-        conn1.setOutputMarkupId(true);
-        add(conn1);
+        filePaths.setOutputMarkupId(true);
+        add(filePaths);
         // -----------------------------------------
 
         // -----------------------------------------
-        // Add Connector Intances (second level)
+        // Add Connector Intances
         // -----------------------------------------
-        final ListView<ConnInstanceTO> conn2 = new ListView<ConnInstanceTO>("conn2", connModel.getObject().getRight()) {
+        final List<List<ConnInstanceTO>> allConns = new ArrayList<>(connModel.getObject().values());
 
-            private static final long serialVersionUID = 6978621871488360381L;
+        final ListView<List<ConnInstanceTO>> conns = new ListView<List<ConnInstanceTO>>("conns", allConns) {
 
-            private final int size = connModel.getObject().getRight().size() + 1;
+            private static final long serialVersionUID = 697862187148836036L;
 
             @Override
-            protected void populateItem(final ListItem<ConnInstanceTO> item) {
-                final ConnInstanceTO conn = item.getModelObject();
+            protected void populateItem(final ListItem<List<ConnInstanceTO>> item) {
 
-                final TopologyNode parent = servers.get(conn.getLocation());
+                final int size = item.getModelObject().size() + 1;
 
-                int kx = size >= 6 ? 800 : (130 * size);
+                final ListView<ConnInstanceTO> conns = new ListView<ConnInstanceTO>("conns", item.getModelObject()) {
 
-                int x = (int) Math.round((parent == null ? origX : parent.getX())
-                        + kx * Math.cos(Math.PI + Math.PI * (item.getIndex() + 1) / size));
-                int y = (int) Math.round((parent == null ? origY : parent.getY())
-                        + 100 * Math.sin(Math.PI + Math.PI * (item.getIndex() + 1) / size));
+                    private static final long serialVersionUID = 6978621871488360381L;
 
-                final TopologyNode topologynode = new TopologyNode(
-                        Long.valueOf(conn.getKey()), conn.getDisplayName(), TopologyNode.Kind.CONNECTOR);
-                topologynode.setConnectinDisplayName(conn.getBundleName());
-                topologynode.setX(x);
-                topologynode.setY(y);
+                    @Override
+                    protected void populateItem(final ListItem<ConnInstanceTO> item) {
+                        final ConnInstanceTO conn = item.getModelObject();
 
-                connectors.put(Long.class.cast(topologynode.getKey()), topologynode);
+                        final TopologyNode topologynode = new TopologyNode(
+                                Long.valueOf(conn.getKey()), conn.getDisplayName(), TopologyNode.Kind.CONNECTOR);
 
-                item.add(topologyNodePanel("conn", topologynode));
+                        // Define the parent note
+                        final TopologyNode parent = servers.get(conn.getLocation());
 
-                if (conn.getLocation().startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) {
-                    final Map<Serializable, TopologyNode> remoteConnections;
+                        // Set the position
+                        int kx = size >= 6 ? 800 : (130 * size);
 
-                    if (connections.containsKey(conn.getLocation())) {
-                        remoteConnections = connections.get(conn.getLocation());
-                    } else {
-                        remoteConnections = new HashMap<>();
-                        connections.put(conn.getLocation(), remoteConnections);
+                        final double hpos;
+                        if (conn.getLocation().startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) {
+                            hpos = Math.PI;
+                        } else {
+                            hpos = 0.0;
+                        }
+
+                        int x = (int) Math.round((parent == null ? origX : parent.getX())
+                                + kx * Math.cos(hpos + Math.PI * (item.getIndex() + 1) / size));
+                        int y = (int) Math.round((parent == null ? origY : parent.getY())
+                                + 100 * Math.sin(hpos + Math.PI * (item.getIndex() + 1) / size));
+
+                        topologynode.setConnectionDisplayName(conn.getBundleName());
+                        topologynode.setX(x);
+                        topologynode.setY(y);
+
+                        connectors.put(Long.class.cast(topologynode.getKey()), topologynode);
+                        item.add(topologyNodePanel("conn", topologynode));
+
+                        // Update connections
+                        final Map<Serializable, TopologyNode> remoteConnections;
+
+                        if (connections.containsKey(conn.getLocation())) {
+                            remoteConnections = connections.get(conn.getLocation());
+                        } else {
+                            remoteConnections = new HashMap<>();
+                            connections.put(conn.getLocation(), remoteConnections);
+                        }
+                        remoteConnections.put(conn.getKey(), topologynode);
                     }
-                    remoteConnections.put(conn.getKey(), topologynode);
-                } else {
-                    syncopeConnections.put(conn.getKey(), topologynode);
-                }
+                };
+
+                conns.setOutputMarkupId(true);
+                item.add(conns);
             }
         };
 
-        conn2.setOutputMarkupId(true);
-        add(conn2);
+        conns.setOutputMarkupId(true);
+        add(conns);
         // -----------------------------------------
 
         // -----------------------------------------
@@ -392,8 +416,6 @@ public class Topology extends BasePage {
         for (ResourceTO resourceTO : resModel.getObject()) {
             final TopologyNode topologynode = new TopologyNode(
                     resourceTO.getKey(), resourceTO.getKey(), TopologyNode.Kind.RESOURCE);
-            topologynode.setX(origX);
-            topologynode.setY(origY);
 
             final Map<Serializable, TopologyNode> remoteConnections;
 
@@ -422,37 +444,37 @@ public class Topology extends BasePage {
                 final ListView<TopologyNode> innerListView = new ListView<TopologyNode>("resources",
                         new ArrayList<>(connections.get(connectorId).values())) {
 
-                    private static final long serialVersionUID = 1L;
-
-                    private final int size = getModelObject().size() + 1;
+                            private static final long serialVersionUID = 1L;
 
-                    @Override
-                    protected void populateItem(final ListItem<TopologyNode> item) {
-                        final TopologyNode topologynode = item.getModelObject();
-                        final TopologyNode parent = connectors.get(connectorId);
+                            private final int size = getModelObject().size() + 1;
 
-                        final double k;
+                            @Override
+                            protected void populateItem(final ListItem<TopologyNode> item) {
+                                final TopologyNode topologynode = item.getModelObject();
+                                final TopologyNode parent = connectors.get(connectorId);
 
-                        if (parent == null || parent.getY() < syncopeTopologyNode.getY()) {
-                            k = Math.PI;
-                        } else {
-                            k = 0.0;
-                        }
+                                // Set position
+                                int kx = size >= 16 ? 800 : (48 * size);
+                                int ky = size < 4 ? 100 : size < 6 ? 350 : 750;
 
-                        int kx = size >= 16 ? 800 : (48 * size);
-                        int ky = size < 4 ? 100 : size < 6 ? 350 : 750;
+                                final double hpos;
+                                if (parent == null || parent.getY() < syncopeTopologyNode.getY()) {
+                                    hpos = Math.PI;
+                                } else {
+                                    hpos = 0.0;
+                                }
 
-                        int x = (int) Math.round((parent == null ? origX : parent.getX())
-                                + kx * Math.cos(k + Math.PI * (item.getIndex() + 1) / size));
-                        int y = (int) Math.round((parent == null ? origY : parent.getY())
-                                + ky * Math.sin(k + Math.PI * (item.getIndex() + 1) / size));
+                                int x = (int) Math.round((parent == null ? origX : parent.getX())
+                                        + kx * Math.cos(hpos + Math.PI * (item.getIndex() + 1) / size));
+                                int y = (int) Math.round((parent == null ? origY : parent.getY())
+                                        + ky * Math.sin(hpos + Math.PI * (item.getIndex() + 1) / size));
 
-                        topologynode.setX(x);
-                        topologynode.setY(y);
+                                topologynode.setX(x);
+                                topologynode.setY(y);
 
-                        item.add(topologyNodePanel("res", topologynode));
-                    }
-                };
+                                item.add(topologyNodePanel("res", topologynode));
+                            }
+                        };
 
                 innerListView.setOutputMarkupId(true);
                 item.add(innerListView);
@@ -466,7 +488,7 @@ public class Topology extends BasePage {
         // -----------------------------------------
         // Create connections
         // -----------------------------------------
-        final WebMarkupContainer jsPlace = new WebMarkupContainer("jsPlace");
+        final WebMarkupContainer jsPlace = new WebMarkupContainerNoVeil("jsPlace");
         jsPlace.setOutputMarkupId(true);
         add(jsPlace);
 
@@ -501,6 +523,24 @@ public class Topology extends BasePage {
             }
         });
         // -----------------------------------------
+
+        newlyCreatedContainer = new WebMarkupContainer("newlyCreatedContainer");
+        newlyCreatedContainer.setOutputMarkupId(true);
+        add(newlyCreatedContainer);
+
+        newlyCreated = new ListView<TopologyNode>("newlyCreated", new ArrayList<TopologyNode>()) {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void populateItem(final ListItem<TopologyNode> item) {
+                item.add(topologyNodePanel("el", item.getModelObject()));
+            }
+        };
+        newlyCreated.setOutputMarkupId(true);
+        newlyCreated.setReuseItems(true);
+
+        newlyCreatedContainer.add(newlyCreated);
     }
 
     private List<String> createConnections(final Map<Serializable, Map<Serializable, TopologyNode>> targets) {
@@ -517,9 +557,9 @@ public class Topology extends BasePage {
         return list;
     }
 
-    private Panel topologyNodePanel(final String id, final TopologyNode node) {
+    private TopologyNodePanel topologyNodePanel(final String id, final TopologyNode node) {
 
-        final Panel panel = new TopologyNodePanel(id, node, getPageReference(), modal);
+        final TopologyNodePanel panel = new TopologyNodePanel(id, node, getPageReference(), modal);
         panel.setMarkupId(String.valueOf(node.getKey()));
         panel.setOutputMarkupId(true);
 
@@ -538,24 +578,43 @@ public class Topology extends BasePage {
     }
 
     @Override
+    @SuppressWarnings("unchecked")
     public void onEvent(final IEvent<?> event) {
         super.onEvent(event);
 
-        if (event.getPayload() instanceof ResourceCreateEvent) {
-            final ResourceCreateEvent resourceCreateEvent = ResourceCreateEvent.class.cast(event.getPayload());
+        if (event.getPayload() instanceof CreateEvent) {
+            final CreateEvent resourceCreateEvent = CreateEvent.class.cast(event.getPayload());
+
+            final TopologyNode node = new TopologyNode(
+                    resourceCreateEvent.getKey(),
+                    resourceCreateEvent.getDisplayName(),
+                    resourceCreateEvent.getKind());
+
+            ((List<TopologyNode>) newlyCreated.getModelObject()).add(node);
+            resourceCreateEvent.getTarget().add(newlyCreatedContainer);
+
             resourceCreateEvent.getTarget().appendJavaScript(String.format(
                     "window.Wicket.WebSocket.send('"
                     + "{\"kind\":\"%s\",\"target\":\"%s\",\"source\":\"%s\",\"scope\":\"%s\"}"
                     + "');",
                     SupportedOperation.ADD_ENDPOINT,
-                    resourceCreateEvent.getResourceTO().getKey(),
-                    resourceCreateEvent.getResourceTO().getConnector(),
-                    TopologyNode.Kind.RESOURCE));
+                    resourceCreateEvent.getKey(),
+                    resourceCreateEvent.getParent(),
+                    resourceCreateEvent.getKind()));
         }
     }
 
-    @Override
-    public String getAjaxIndicatorMarkupId() {
-        return StringUtils.EMPTY;
+    private static class WebMarkupContainerNoVeil extends WebMarkupContainer implements IAjaxIndicatorAware {
+
+        private static final long serialVersionUID = 1L;
+
+        public WebMarkupContainerNoVeil(final String id) {
+            super(id);
+        }
+
+        @Override
+        public String getAjaxIndicatorMarkupId() {
+            return StringUtils.EMPTY;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNode.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNode.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNode.java
index f7c8aaa..ab727a0 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNode.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNode.java
@@ -27,6 +27,7 @@ public class TopologyNode implements Serializable {
         RESOURCE,
         CONNECTOR,
         CONNECTOR_SERVER,
+        FS_PATH,
         SYNCOPE
 
     }
@@ -76,8 +77,8 @@ public class TopologyNode implements Serializable {
         return connectionDisplayName;
     }
 
-    public void setConnectinDisplayName(final String connectinDisplayName) {
-        this.connectionDisplayName = connectinDisplayName;
+    public void setConnectionDisplayName(final String connectionDisplayName) {
+        this.connectionDisplayName = connectionDisplayName;
     }
 
     public Kind getKind() {

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java
index 478260e..3dc7c48 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java
@@ -27,11 +27,13 @@ import org.apache.syncope.client.console.rest.ConnectorRestClient;
 import org.apache.syncope.client.console.rest.ResourceRestClient;
 import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
 import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.ConnInstanceTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.behavior.AttributeAppender;
 import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.panel.Fragment;
@@ -72,20 +74,29 @@ public class TopologyNodePanel extends Panel {
         switch (node.getKind()) {
             case SYNCOPE:
                 title = "";
-                add(getSyncopeFragment(node, pageRef));
+                add(getSyncopeFragment());
+                add(new AttributeAppender("class", "topology_root", " "));
                 break;
             case CONNECTOR_SERVER:
                 title = node.getDisplayName();
-                add(getConnectorServerFragment(node, pageRef));
+                add(getLocationFragment(node, pageRef));
+                add(new AttributeAppender("class", "topology_cs", " "));
+                break;
+            case FS_PATH:
+                title = node.getDisplayName();
+                add(getLocationFragment(node, pageRef));
+                add(new AttributeAppender("class", "topology_cs", " "));
                 break;
             case CONNECTOR:
                 title = (StringUtils.isBlank(node.getConnectionDisplayName())
                         ? "" : node.getConnectionDisplayName() + ":") + node.getDisplayName();
                 add(getConnectorFragment(node, pageRef));
+                add(new AttributeAppender("class", "topology_conn", " "));
                 break;
             default:
                 title = node.getDisplayName().length() > 20 ? node.getDisplayName() : "";
                 add(getResurceFragment(node, pageRef));
+                add(new AttributeAppender("class", "topology_res", " "));
         }
 
         if (StringUtils.isNotEmpty(title)) {
@@ -97,20 +108,34 @@ public class TopologyNodePanel extends Panel {
         this.modal = modal;
     }
 
-    private Fragment getSyncopeFragment(final TopologyNode node, final PageReference pageRef) {
-        final Fragment fragment = new Fragment("actions", "syncopeActions", this);
-        fragment.setOutputMarkupId(true);
-        return fragment;
+    private Fragment getSyncopeFragment() {
+        return new Fragment("actions", "syncopeActions", this);
     }
 
-    private Fragment getConnectorServerFragment(final TopologyNode node, final PageReference pageRef) {
-        final Fragment fragment = new Fragment("actions", "syncopeActions", this);
+    private Fragment getLocationFragment(final TopologyNode node, final PageReference pageRef) {
+        final Fragment fragment = new Fragment("actions", "locationActions", this);
+
+        final AjaxLink<String> create = new ClearIndicatingAjaxLink<String>("create", pageRef) {
+
+            private static final long serialVersionUID = 3776750333491622263L;
+
+            @Override
+            public void onClickInternal(final AjaxRequestTarget target) {
+
+                final ConnInstanceTO connectorTO = new ConnInstanceTO();
+                connectorTO.setLocation(node.getKey().toString());
+                modal.setContent(new ConnectorModal(modal, pageRef, connectorTO));
+                modal.setTitle(MessageFormat.format(getString("connector.new"), node.getKey()));
+                modal.show(target);
+            }
+        };
+        fragment.add(create);
+
         return fragment;
     }
 
     private Fragment getConnectorFragment(final TopologyNode node, final PageReference pageRef) {
-        final Fragment fragment = new Fragment("actions", "connectorWithNoResourceActions", this);
-        fragment.setOutputMarkupId(true);
+        final Fragment fragment = new Fragment("actions", "connectorActions", this);
 
         final AjaxLink<String> delete = new ClearIndicatingAjaxLink<String>("delete", pageRef) {
 
@@ -139,9 +164,7 @@ public class TopologyNodePanel extends Panel {
                 final ResourceTO resourceTO = new ResourceTO();
                 resourceTO.setConnector(Long.class.cast(node.getKey()));
                 resourceTO.setConnectorDisplayName(node.getDisplayName());
-
                 modal.setContent(new ResourceModal(modal, pageRef, resourceTO, true));
-
                 modal.setTitle(getString("resource.new"));
                 modal.show(target);
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AbstractFieldPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AbstractFieldPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AbstractFieldPanel.java
index 30bb47c..41643ea 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AbstractFieldPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/AbstractFieldPanel.java
@@ -36,5 +36,5 @@ public abstract class AbstractFieldPanel<T> extends Panel {
         super(id, model);
     }
 
-    public abstract AbstractFieldPanel setModelObject(T object);
+    public abstract AbstractFieldPanel<T> setModelObject(T object);
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
index 71bcc0f..ec405a2 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
@@ -21,14 +21,27 @@ package org.apache.syncope.client.console.wicket.markup.html.form;
 import java.io.Serializable;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 
-public abstract class ActionLink implements Serializable {
+public abstract class ActionLink<T> implements Serializable {
 
     private static final long serialVersionUID = 7031329706998320639L;
 
     private boolean reloadFeedbackPanel = true;
 
+    private T modelObject;
+
+    public ActionLink() {
+    }
+
+    public ActionLink(final T modelObject) {
+        this.modelObject = modelObject;
+    }
+
     public enum ActionType {
 
+        MAPPING("update"),
+        ACCOUNT_LINK("update"),
+        RESET_TIME("update"),
+        CLONE("create"),
         CREATE("create"),
         EDIT("read"),
         USER_TEMPLATE("read"),
@@ -69,7 +82,11 @@ public abstract class ActionLink implements Serializable {
         }
     }
 
-    public abstract void onClick(final AjaxRequestTarget target);
+    public T getModelObject() {
+        return modelObject;
+    }
+
+    public abstract void onClick(final AjaxRequestTarget target, final T modelObject);
 
     public void postClick() {
     }
@@ -78,7 +95,7 @@ public abstract class ActionLink implements Serializable {
         return reloadFeedbackPanel;
     }
 
-    public ActionLink feedbackPanelAutomaticReload(final boolean reloadFeedbackPanel) {
+    public ActionLink<T> feedbackPanelAutomaticReload(final boolean reloadFeedbackPanel) {
         this.reloadFeedbackPanel = reloadFeedbackPanel;
         return this;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
index 433f9f5..868f6a2 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
@@ -18,6 +18,11 @@
  */
 package org.apache.syncope.client.console.wicket.markup.html.form;
 
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.apache.commons.lang3.tuple.Triple;
 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.wicket.PageReference;
@@ -26,24 +31,34 @@ import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDa
 import org.apache.wicket.markup.html.panel.Fragment;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
 
 /**
  * This empty class must exist because there not seems to be alternative to provide specialized HTML for edit links.
+ *
+ * @param <T> model object type.
  */
-public class ActionLinksPanel extends Panel {
+public final class ActionLinksPanel<T extends Serializable> extends Panel {
 
     private static final long serialVersionUID = 322966537010107771L;
 
     private final PageReference pageRef;
 
-    public ActionLinksPanel(final String componentId, final IModel<?> model, final PageReference pageRef) {
+    private final IModel<T> model;
+
+    private ActionLinksPanel(final String componentId, final IModel<T> model, final PageReference pageRef) {
         super(componentId, model);
+        this.model = model;
         this.pageRef = pageRef;
 
         super.add(new Fragment("panelClaim", "emptyFragment", this));
         super.add(new Fragment("panelManageResources", "emptyFragment", this));
         super.add(new Fragment("panelManageUsers", "emptyFragment", this));
         super.add(new Fragment("panelManageGroups", "emptyFragment", this));
+        super.add(new Fragment("panelMapping", "emptyFragment", this));
+        super.add(new Fragment("panelAccountLink", "emptyFragment", this));
+        super.add(new Fragment("panelResetTime", "emptyFragment", this));
+        super.add(new Fragment("panelClone", "emptyFragment", this));
         super.add(new Fragment("panelCreate", "emptyFragment", this));
         super.add(new Fragment("panelEdit", "emptyFragment", this));
         super.add(new Fragment("panelReset", "emptyFragment", this));
@@ -68,29 +83,13 @@ public class ActionLinksPanel extends Panel {
         super.add(new Fragment("panelProvision", "emptyFragment", this));
         super.add(new Fragment("panelZoomIn", "emptyFragment", this));
         super.add(new Fragment("panelZoomOut", "emptyFragment", this));
-
-    }
-
-    public ActionLinksPanel add(
-            final ActionLink link, final ActionLink.ActionType type, final String entitlements) {
-
-        return addWithRoles(link, type, entitlements, true);
     }
 
-    public ActionLinksPanel add(
-            final ActionLink link, final ActionLink.ActionType type, final String entitlement, final boolean enabled) {
-
-        return addWithRoles(link, type, entitlement, enabled);
-    }
-
-    public ActionLinksPanel addWithRoles(
-            final ActionLink link, final ActionLink.ActionType type, final String entitlements) {
-
-        return addWithRoles(link, type, entitlements, true);
-    }
-
-    public ActionLinksPanel addWithRoles(
-            final ActionLink link, final ActionLink.ActionType type, final String entitlements, final boolean enabled) {
+    public ActionLinksPanel<T> add(
+            final ActionLink<T> link,
+            final ActionLink.ActionType type,
+            final String entitlements,
+            final boolean enabled) {
 
         Fragment fragment = null;
 
@@ -105,7 +104,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -119,7 +118,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -133,7 +132,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -147,7 +146,63 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case MAPPING:
+                fragment = new Fragment("panelMapping", "fragmentMapping", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("mappingLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target, model.getObject());
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case ACCOUNT_LINK:
+                fragment = new Fragment("panelAccountLink", "fragmentAccountLink", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("accountLinkLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target, model.getObject());
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case RESET_TIME:
+                fragment = new Fragment("panelResetTime", "fragmentResetTime", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("resetTimeLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target, model.getObject());
+                    }
+                }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
+                break;
+
+            case CLONE:
+                fragment = new Fragment("panelClone", "fragmentClone", this);
+
+                fragment.addOrReplace(new ClearIndicatingAjaxLink<Void>("cloneLink", pageRef) {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    protected void onClickInternal(final AjaxRequestTarget target) {
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -161,7 +216,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -175,7 +230,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 });
                 break;
@@ -189,7 +244,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -203,7 +258,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -217,7 +272,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -231,7 +286,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -245,7 +300,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -259,7 +314,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -273,7 +328,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -287,7 +342,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
 
@@ -302,7 +357,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
 
@@ -317,7 +372,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -331,7 +386,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -345,7 +400,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -359,7 +414,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -373,7 +428,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -388,7 +443,7 @@ public class ActionLinksPanel extends Panel {
 
                             @Override
                             protected void onClickInternal(final AjaxRequestTarget target) {
-                                link.onClick(target);
+                                link.onClick(target, model.getObject());
                             }
                         }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -402,7 +457,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -417,7 +472,7 @@ public class ActionLinksPanel extends Panel {
 
                             @Override
                             protected void onClickInternal(final AjaxRequestTarget target) {
-                                link.onClick(target);
+                                link.onClick(target, model.getObject());
                             }
                         }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -431,7 +486,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -446,7 +501,7 @@ public class ActionLinksPanel extends Panel {
 
                             @Override
                             protected void onClickInternal(final AjaxRequestTarget target) {
-                                link.onClick(target);
+                                link.onClick(target, model.getObject());
                             }
                         }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -460,7 +515,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -473,7 +528,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -486,7 +541,7 @@ public class ActionLinksPanel extends Panel {
 
                     @Override
                     protected void onClickInternal(final AjaxRequestTarget target) {
-                        link.onClick(target);
+                        link.onClick(target, model.getObject());
                     }
                 }.feedbackPanelAutomaticReload(link.feedbackPanelAutomaticReload()));
                 break;
@@ -521,6 +576,22 @@ public class ActionLinksPanel extends Panel {
                 super.addOrReplace(new Fragment("panelManageGroups", "emptyFragment", this));
                 break;
 
+            case MAPPING:
+                super.addOrReplace(new Fragment("panelMapping", "emptyFragment", this));
+                break;
+
+            case ACCOUNT_LINK:
+                super.addOrReplace(new Fragment("panelAccountLink", "emptyFragment", this));
+                break;
+
+            case RESET_TIME:
+                super.addOrReplace(new Fragment("panelResetTime", "emptyFragment", this));
+                break;
+
+            case CLONE:
+                super.addOrReplace(new Fragment("panelClone", "emptyFragment", this));
+                break;
+
             case CREATE:
                 super.addOrReplace(new Fragment("panelCreate", "emptyFragment", this));
                 break;
@@ -606,4 +677,92 @@ public class ActionLinksPanel extends Panel {
             // do nothing
         }
     }
+
+    public static <T extends Serializable> Builder<T> builder(final PageReference pageRef) {
+        return new Builder<T>(pageRef);
+    }
+
+    /**
+     * ActionLinksPanel builder.
+     *
+     * @param <T> model object type.
+     */
+    public static final class Builder<T extends Serializable> implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        private final Map<ActionLink.ActionType, Triple<ActionLink<T>, String, Boolean>> actions = new HashMap<>();
+
+        private final PageReference pageRef;
+
+        private Builder(final PageReference pageRef) {
+            this.pageRef = pageRef;
+        }
+
+        public Builder<T> add(
+                final ActionLink<T> link,
+                final ActionLink.ActionType type,
+                final String entitlements) {
+
+            return addWithRoles(link, type, entitlements, true);
+        }
+
+        public Builder<T> add(
+                final ActionLink<T> link,
+                final ActionLink.ActionType type,
+                final String entitlement,
+                final boolean enabled) {
+
+            return addWithRoles(link, type, entitlement, enabled);
+        }
+
+        public Builder<T> addWithRoles(
+                final ActionLink<T> link,
+                final ActionLink.ActionType type,
+                final String entitlements) {
+
+            return addWithRoles(link, type, entitlements, true);
+        }
+
+        public Builder<T> addWithRoles(
+                final ActionLink<T> link,
+                final ActionLink.ActionType type,
+                final String entitlements,
+                final boolean enabled) {
+            actions.put(type, Triple.of(link, entitlements, enabled));
+            return this;
+        }
+
+        /**
+         * Use this method to build an ation panel without any model reference.
+         *
+         * @param id Component id.
+         * @return Action link panel.
+         */
+        public ActionLinksPanel<T> build(final String id) {
+            return build(id, null);
+        }
+
+        /**
+         * Use this methos to build an action panel including a model reference.
+         *
+         * @param id Component id.
+         * @param modelObject model object.
+         * @return Action link panel.
+         */
+        public ActionLinksPanel<T> build(final String id, final T modelObject) {
+            final ActionLinksPanel<T> panel = modelObject == null
+                    ? new ActionLinksPanel<T>(id, new Model<T>(), this.pageRef)
+                    : new ActionLinksPanel<T>(id, new Model<T>(modelObject), this.pageRef);
+
+            for (Entry<ActionLink.ActionType, Triple<ActionLink<T>, String, Boolean>> action : actions.entrySet()) {
+                panel.add(
+                        action.getValue().getLeft(),
+                        action.getKey(),
+                        action.getValue().getMiddle(),
+                        action.getValue().getRight());
+            }
+            return panel;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/CheckBoxMultipleChoiceFieldPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/CheckBoxMultipleChoiceFieldPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/CheckBoxMultipleChoiceFieldPanel.java
index 3c5119b..dc7bfec 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/CheckBoxMultipleChoiceFieldPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/CheckBoxMultipleChoiceFieldPanel.java
@@ -19,6 +19,9 @@
 package org.apache.syncope.client.console.wicket.markup.html.form;
 
 import java.util.List;
+import org.apache.wicket.Component;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.markup.html.form.AbstractChoice;
 
 import org.apache.wicket.markup.html.form.CheckBoxMultipleChoice;
 import org.apache.wicket.model.IModel;
@@ -35,7 +38,10 @@ public class CheckBoxMultipleChoiceFieldPanel<E> extends AbstractFieldPanel<List
         super(id, model);
 
         field = new CheckBoxMultipleChoice<E>("checkBoxMultipleChoice", model, choices);
-        add(field);
+        add(field.
+                setPrefix("<div class=\"checkbox\">").
+                setSuffix("</div>").
+                setLabelPosition(AbstractChoice.LabelPosition.WRAP_AFTER));
     }
 
     @Override
@@ -43,4 +49,9 @@ public class CheckBoxMultipleChoiceFieldPanel<E> extends AbstractFieldPanel<List
         field.setModelObject(object);
         return this;
     }
+
+    @Override
+    public Component add(final Behavior... behaviors) {
+        return field.add(behaviors);
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizard.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizard.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizard.java
new file mode 100644
index 0000000..d9a42c1
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizard.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.syncope.client.console.wizards;
+
+import java.io.Serializable;
+import org.apache.commons.lang3.SerializationUtils;
+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.wizard.Wizard;
+import org.apache.wicket.request.cycle.RequestCycle;
+
+public abstract class AjaxWizard<T extends Serializable> extends Wizard {
+
+    private static final long serialVersionUID = 1L;
+
+    private final PageReference pageRef;
+
+    private final T item;
+
+    /**
+     * Construct.
+     *
+     * @param id The component id
+     * @param item
+     * @param pageRef Caller page reference.
+     */
+    public AjaxWizard(final String id, final T item, final PageReference pageRef) {
+        super(id);
+        this.item = item;
+        this.pageRef = pageRef;
+        setOutputMarkupId(true);
+    }
+
+    @Override
+    protected Component newButtonBar(final String id) {
+        return new AjaxWizardButtonBar(id, this);
+    }
+
+    protected abstract void onCancelInternal();
+
+    protected abstract void onApplyInternal();
+
+    /**
+     * @see org.apache.wicket.extensions.wizard.Wizard#onCancel()
+     */
+    @Override
+    public final void onCancel() {
+        onCancelInternal();
+        send(pageRef.getPage(), Broadcast.DEPTH,
+                new NewItemCancelEvent<T>(item, RequestCycle.get().find(AjaxRequestTarget.class)));
+    }
+
+    /**
+     * @see org.apache.wicket.extensions.wizard.Wizard#onFinish()
+     */
+    @Override
+    public final void onFinish() {
+        onApplyInternal();
+        send(pageRef.getPage(), Broadcast.DEPTH,
+                new NewItemFinishEvent<T>(item, RequestCycle.get().find(AjaxRequestTarget.class)));
+    }
+
+    public T getItem() {
+        return item;
+    }
+
+    public abstract static class NewItemEvent<T> {
+        private final T item;
+
+        private final AjaxRequestTarget target;
+
+        public NewItemEvent(final T item, final AjaxRequestTarget target) {
+            this.item = item;
+            this.target = target;
+        }
+
+        public T getItem() {
+            return item;
+        }
+
+        public AjaxRequestTarget getTarget() {
+            return target;
+        }
+    }
+
+    public static class NewItemCancelEvent<T> extends NewItemEvent<T> {
+
+        public NewItemCancelEvent(final T item, final AjaxRequestTarget target) {
+            super(item, target);
+        }
+
+    }
+
+    public static class NewItemFinishEvent<T> extends NewItemEvent<T> {
+
+        public NewItemFinishEvent(final T item, final AjaxRequestTarget target) {
+            super(item, target);
+        }
+
+    }
+
+    /**
+     *
+     * @return
+     */
+    @Override
+    public AjaxWizard<T> clone() {
+        return SerializationUtils.clone(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButton.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButton.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButton.java
new file mode 100644
index 0000000..a581954
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButton.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.syncope.client.console.wizards;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.extensions.wizard.IWizard;
+import org.apache.wicket.extensions.wizard.IWizardModel;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.ResourceModel;
+
+public abstract class AjaxWizardButton extends AjaxButton {
+
+    private static final long serialVersionUID = 1L;
+
+    private final IWizard wizard;
+
+    public AjaxWizardButton(
+            final String id,
+            final IWizard wizard,
+            final Form<?> form,
+            final String labelResourceKey,
+            final boolean formprocessing) {
+        super(id, form);
+        this.setLabel(new ResourceModel(labelResourceKey));
+        this.wizard = wizard;
+        setDefaultFormProcessing(formprocessing);
+    }
+
+    public AjaxWizardButton(final String id, final IWizard wizard, final String labelResourceKey) {
+        this(id, wizard, null, labelResourceKey, true);
+    }
+
+    public AjaxWizardButton(
+            final String id, final IWizard wizard, final String labelResourceKey, final boolean formprocessing) {
+        this(id, wizard, null, labelResourceKey, formprocessing);
+    }
+
+    protected final IWizard getWizard() {
+        return wizard;
+    }
+
+    protected final IWizardModel getWizardModel() {
+        return getWizard().getWizardModel();
+    }
+
+    @Override
+    protected final void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+        onClick(target, form);
+    }
+
+    protected abstract void onClick(final AjaxRequestTarget target, final Form<?> form);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButtonBar.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButtonBar.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButtonBar.java
new file mode 100644
index 0000000..4f31a26
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AjaxWizardButtonBar.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.syncope.client.console.wizards;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.wizard.IWizardModel;
+import org.apache.wicket.extensions.wizard.IWizardStep;
+import org.apache.wicket.extensions.wizard.Wizard;
+import org.apache.wicket.extensions.wizard.WizardButtonBar;
+import org.apache.wicket.markup.html.form.Form;
+
+public class AjaxWizardButtonBar extends WizardButtonBar {
+
+    private static final long serialVersionUID = 1L;
+
+    public AjaxWizardButtonBar(final String id, final Wizard wizard) {
+        super(id, wizard);
+
+        addOrReplace(new AjaxWizardButton("next", wizard, "next") {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void onClick(final AjaxRequestTarget target, final Form<?> form) {
+                IWizardModel wizardModel = getWizardModel();
+                IWizardStep step = wizardModel.getActiveStep();
+
+                // let the step apply any state
+                step.applyState();
+
+                // if the step completed after applying the state, move the model onward
+                if (step.isComplete()) {
+                    wizardModel.next();
+                } else {
+                    error(getLocalizer().getString(
+                            "org.apache.wicket.extensions.wizard.NextButton.step.did.not.complete", this));
+                }
+
+                target.add(wizard);
+            }
+
+            @Override
+            public final boolean isEnabled() {
+                return super.isEnabled() && getWizardModel().isNextAvailable();
+            }
+        });
+
+        addOrReplace(new AjaxWizardButton("previous", wizard, "prev", false) {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void onClick(final AjaxRequestTarget target, final Form<?> form) {
+                getWizardModel().previous();
+                target.add(wizard);
+            }
+
+            @Override
+            public final boolean isEnabled() {
+                return super.isEnabled() && getWizardModel().isPreviousAvailable();
+            }
+        });
+
+        addOrReplace(new AjaxWizardButton("cancel", wizard, "cancel", false) {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void onClick(final AjaxRequestTarget target, final Form<?> form) {
+                getWizardModel().cancel();
+                target.add(wizard);
+            }
+
+            @Override
+            public final boolean isEnabled() {
+                return true;
+            }
+        });
+
+        addOrReplace(new AjaxWizardButton("finish", wizard, "finish") {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void onClick(final AjaxRequestTarget target, final Form<?> form) {
+                getWizardModel().finish();
+                target.add(wizard);
+            }
+
+            @Override
+            public final boolean isEnabled() {
+                final IWizardStep activeStep = getWizardModel().getActiveStep();
+                return (activeStep != null) && getWizardModel().isLastStep(activeStep) && super.isEnabled();
+            }
+        });
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/java/org/apache/syncope/client/console/wizards/ProvisionWizard.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/ProvisionWizard.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/ProvisionWizard.java
new file mode 100644
index 0000000..6c3c8e0
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/ProvisionWizard.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2015 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.syncope.client.console.wizards;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.panels.ResourceMappingPanel;
+import org.apache.syncope.common.lib.to.ProvisionTO;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.extensions.wizard.WizardModel;
+import org.apache.wicket.extensions.wizard.WizardStep;
+import org.apache.wicket.markup.html.form.TextField;
+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.model.StringResourceModel;
+
+public class ProvisionWizard extends AjaxWizard<ProvisionTO> {
+
+    private static final long serialVersionUID = 1L;
+
+    private final ResourceTO resourceTO;
+
+    /**
+     * The object type specification step.
+     */
+    private final class ObjectType extends WizardStep {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * Construct.
+         */
+        public ObjectType() {
+            super(new ResourceModel("type.title", StringUtils.EMPTY),
+                    new ResourceModel("type.summary", StringUtils.EMPTY), new Model<ProvisionTO>(getItem()));
+
+            add(new TextField<String>(
+                    "type", new PropertyModel<String>(getItem(), "anyType")).setRequired(true));
+            add(new TextField<String>(
+                    "class", new PropertyModel<String>(getItem(), "objectClass")).setRequired(true));
+        }
+    }
+
+    /**
+     * Mapping definition step.
+     */
+    private final class Mapping extends WizardStep {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * Construct.
+         */
+        public Mapping() {
+            setTitleModel(new ResourceModel("mapping.title", "Mapping"));
+            setSummaryModel(new StringResourceModel("mapping.summary", this, new Model<ProvisionTO>(getItem())));
+
+            add(new ResourceMappingPanel("mapping", resourceTO, getItem()));
+        }
+    }
+
+    /**
+     * AccountLink specification step.
+     */
+    private final class AccountLink extends WizardStep {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * Construct.
+         */
+        public AccountLink() {
+            super(new ResourceModel("link.title", StringUtils.EMPTY),
+                    new ResourceModel("link.summary", StringUtils.EMPTY));
+        }
+    }
+
+    /**
+     * Construct.
+     *
+     * @param id The component id
+     * @param resourceTO external resource to be updated.
+     * @param pageRef Caller page reference.
+     */
+    public ProvisionWizard(final String id, final ResourceTO resourceTO, final PageReference pageRef) {
+        super(id, new ProvisionTO(), pageRef);
+        this.resourceTO = resourceTO;
+
+        setDefaultModel(new CompoundPropertyModel<ProvisionWizard>(this));
+
+        final WizardModel model = new WizardModel();
+        model.add(new ObjectType());
+        model.add(new Mapping());
+        model.add(new AccountLink());
+
+        init(model);
+    }
+
+    @Override
+    protected void onCancelInternal() {
+        // d nothing
+    }
+
+    @Override
+    protected void onApplyInternal() {
+        // do nothing
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css b/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
index 1b8e565..484382e 100644
--- a/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
+++ b/client/console/src/main/resources/META-INF/resources/css/syncopeConsole.css
@@ -17,129 +17,134 @@
  * under the License.
  */
 .feedbackPanel {
-    padding-left: 0px;
-    text-align: center;
+  padding-left: 0px;
+  text-align: center;
 }
 
 .notificationpanel_row {  
-    list-style-type: none;
+  list-style-type: none;
 }  
 
 .notificationpanel_row span {  
-    border:0 none;
+  border:0 none;
 }    
 pre {
-    white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */
-    white-space: -pre-wrap; /* Opera */
-    white-space: -o-pre-wrap; /* Opera */
-    white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation) http://www.w3.org/TR/css3-text/#white-space */
-    word-wrap: break-word; /* IE 5.5+ */
+  white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */
+  white-space: -pre-wrap; /* Opera */
+  white-space: -o-pre-wrap; /* Opera */
+  white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation) http://www.w3.org/TR/css3-text/#white-space */
+  word-wrap: break-word; /* IE 5.5+ */
 }
 
 #veil {
-    display:none;
-    position:absolute;
-    top:0;
-    left:0;
-    z-index:99999;
-    background-color:black;
-    width:100%;
-    height:20000px;
-    color:white;
-    opacity:0.3;
-    filter:alpha(opacity=30);
+  display:none;
+  position:absolute;
+  top:0;
+  left:0;
+  z-index:99999;
+  background-color:black;
+  width:100%;
+  height:20000px;
+  color:white;
+  opacity:0.3;
+  filter:alpha(opacity=30);
 }
 
 #veil img {
-    position:absolute;
-    top:300px;
-    left:50%;
-    margin-left:-75px;
-    width:150px;
+  position:absolute;
+  top:300px;
+  left:50%;
+  margin-left:-75px;
+  width:150px;
 }
 
 .block-sidebar {
-    max-height: 100%; 
-    overflow: auto; 
-    padding-top: 90px; 
-    padding-bottom: 50px; 
-    position: fixed;
+  max-height: 100%; 
+  overflow: auto; 
+  padding-top: 90px; 
+  padding-bottom: 50px; 
+  position: fixed;
 }
 
 .inner-control-sidebar {
-    position: fixed; 
-    height: auto;
+  position: fixed; 
+  height: auto;
 }
 
 .content-margin-layout {
-    margin: 0px 230px 0px 0px !important;
-    padding: 20px !important;
+  margin: 0px 230px 0px 0px !important;
+  padding: 20px !important;
 }
 
 .admin-content-page {
-    padding: 20px;
-    background: #ecf0f5
+  padding: 20px;
+  background: #ecf0f5
 }
 
 .realms {
-    min-height: 554px
+  min-height: 554px
 }
 
 .actions > li > a {
-    padding-top: 5px !important;
-    padding-bottom: 5px !important;
+  padding-top: 5px !important;
+  padding-bottom: 5px !important;
+}
+
+div.listview-actions a{
+  float:left; 
+  padding-right:8px
 }
 
 .block-header {
-    position: fixed;
-    width: 100%;
-    top: 0;
+  position: fixed;
+  width: 100%;
+  top: 0;
 }
 
 .block-footer {
-    position: fixed;
-    width: 100%;
-    bottom: 0px;
+  position: fixed;
+  width: 100%;
+  bottom: 0px;
 }
 
 .logo-pos {
-    padding-top: 4px !important;
-    overflow: visible !important;
+  padding-top: 4px !important;
+  overflow: visible !important;
 }
 
 .angle {
-    border: medium none !important;
-    cursor: pointer;
-    display: inline-table !important;
-    float: right;
-    height: 30px;
-    overflow: hidden;
-    position: relative !important;
-    right: 0;
-    top: -30px;
-    width: 25%;
-    z-index: 3;
+  border: medium none !important;
+  cursor: pointer;
+  display: inline-table !important;
+  float: right;
+  height: 30px;
+  overflow: hidden;
+  position: relative !important;
+  right: 0;
+  top: -30px;
+  width: 25%;
+  z-index: 3;
 }
 
 @media (min-width: 768px) {
-    .main-header .logo {
-	height: 54px;
-    }
+  .main-header .logo {
+    height: 54px;
+  }
 }
 
 .w_caption h3 {
-    font-size: 16px;
+  font-size: 16px;
 }
 
 div.wicket-modal div.w_content_3 {
-    border: 1px solid #eee;
-    border-radius: 20px;
-    padding: 5px;
+  border: 1px solid #eee;
+  border-radius: 20px;
+  padding: 5px;
 }
 
 .tab-content {
-    margin-bottom: 10px;
-    margin-top: 10px;
+  margin-bottom: 10px;
+  margin-top: 10px;
 }
 
 a.help {

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/resources/META-INF/resources/js/topology.js
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/META-INF/resources/js/topology.js b/client/console/src/main/resources/META-INF/resources/js/topology.js
index f2a7ac3..9327b01 100644
--- a/client/console/src/main/resources/META-INF/resources/js/topology.js
+++ b/client/console/src/main/resources/META-INF/resources/js/topology.js
@@ -107,18 +107,24 @@ var enabledEndpointStyle = {
 };
 
 window.disable = function(targetName){
-    jsPlumb.select({target:targetName}).setPaintStyle(disabledConnectorStyle).setHoverPaintStyle(disabledConnectorHoverStyle);
-    jsPlumb.selectEndpoints({element: [targetName]}).setPaintStyle(disabledEndpointStyle);
+    jsPlumb.ready(function(){
+	jsPlumb.select({target:targetName}).setPaintStyle(disabledConnectorStyle).setHoverPaintStyle(disabledConnectorHoverStyle);
+	jsPlumb.selectEndpoints({element: [targetName]}).setPaintStyle(disabledEndpointStyle);
+    });
 }
 
 window.enable = function(targetName){
-    jsPlumb.select({target:targetName}).setPaintStyle(enabledConnectorStyle).setHoverPaintStyle(enabledConnectorHoverStyle);
-    jsPlumb.selectEndpoints({element: [targetName]}).setPaintStyle(enabledEndpointStyle);
+    jsPlumb.ready(function(){
+	jsPlumb.select({target:targetName}).setPaintStyle(enabledConnectorStyle).setHoverPaintStyle(enabledConnectorHoverStyle);
+	jsPlumb.selectEndpoints({element: [targetName]}).setPaintStyle(enabledEndpointStyle);
+    });
 }
 
 window.failure = function(targetName){
-    jsPlumb.select({target:targetName}).setPaintStyle(failedConnectorStyle).setHoverPaintStyle(failedConnectorHoverStyle);
-    jsPlumb.selectEndpoints({element: [targetName]}).setPaintStyle(failedEndpointStyle);
+    jsPlumb.ready(function(){
+	jsPlumb.select({target:targetName}).setPaintStyle(failedConnectorStyle).setHoverPaintStyle(failedConnectorHoverStyle);
+	jsPlumb.selectEndpoints({element: [targetName]}).setPaintStyle(failedEndpointStyle);
+    });
 }
 
 window.unknown = function(targetName){
@@ -221,61 +227,57 @@ window.zoomOut = function(el, instance, transformOrigin) {
 };
 
 window.connect = function(source, target, scope){
-    if(jsPlumb.select({source:source, target:target, scope: scope}) !=null){
-	jsPlumb.connect({source:source, target:target, scope: scope}, def);
-    }
+    jsPlumb.ready(function(){
+	if(jsPlumb.select({source:source, target:target, scope: scope}) != null){
+	    jsPlumb.connect({source:source, target:target, scope: scope}, def);
+	}
+    });
 }
 
 window.activate = function(zoom){
-    jsPlumb.draggable(jsPlumb.getSelector(".window"));
-    jsPlumb.setContainer("drawing");
-
-    $("#drawing").draggable({
-	containment: 'topology',
-	cursor: 'move'
+    jsPlumb.ready(function(){
+	jsPlumb.draggable(jsPlumb.getSelector(".window"));
+	jsPlumb.setContainer("drawing");
+	
+	jsPlumb.Defaults.MaxConnections = 1000;
+	
+	$("#drawing").draggable({
+	    containment: 'topology',
+	    cursor: 'move'
+	});
+	
+	var val = getTopology();
+	if(val.__zoom__ == null){
+	    setZoom($("#drawing")[0], zoom);
+	} else {
+	    setZoom($("#drawing")[0], val.__zoom__);
+	}
     });
-
-    var val = getTopology();
-    if(val.__zoom__ == null){
-	setZoom($("#drawing")[0], zoom);
-    } else {
-	setZoom($("#drawing")[0], val.__zoom__);
-    }
 }
 
 window.checkConnection = function() {
-    jsPlumb.select({scope:"CONNECTOR"}).each(function(connection) {
-        Wicket.WebSocket.send("{ \"kind\":\"CHECK_CONNECTOR\", \"target\":\"" + connection.target.id + "\" }");
-    });
-    jsPlumb.select({scope:"RESOURCE"}).each(function(connection) {
-        Wicket.WebSocket.send("{ \"kind\":\"CHECK_RESOURCE\", \"target\":\"" + connection.target.id + "\" }");
+    jsPlumb.ready(function(){
+	jsPlumb.select({scope:"CONNECTOR"}).each(function(connection) {
+            Wicket.WebSocket.send("{ \"kind\":\"CHECK_CONNECTOR\", \"target\":\"" + connection.target.id + "\" }");
+	});
+	jsPlumb.select({scope:"RESOURCE"}).each(function(connection) {
+            Wicket.WebSocket.send("{ \"kind\":\"CHECK_RESOURCE\", \"target\":\"" + connection.target.id + "\" }");
+	});
     });
 }
 
 window.addEndpoint = function(source, target, scope) {
     var sourceElement = $('#' + source);
-    var element = sourceElement.clone();
-    element.attr('id', target);
-    element.removeAttr('data-original-title');
     
     var top = parseFloat(sourceElement.css("top")) + 10;
     var left = parseFloat(sourceElement.css("left")) - 150;
 
-    if(scope == 'RESOURCE'){
-	var style = 'topology_res';
-    }else{
-	var style = 'topology_conn';
-    }
-    
-    element.attr('class', 'window jsplumb-draggable _jsPlumb_endpoint_anchor_ ' + style);
-    
-    element.find('p').text(target);
-    
-    $('#drawing').append(element);
     setPosition(target, left, top);
-    
-    jsPlumb.draggable(element);
-    jsPlumb.connect({ source:source, target:target, scope:scope }, def);
+
+    jsPlumb.ready(function(){
+	jsPlumb.draggable(jsPlumb.getSelector("#" + target));
+	jsPlumb.connect({ source:source, target:target, scope:scope }, def);
+    });
 }
 
 jsPlumb.importDefaults({

http://git-wip-us.apache.org/repos/asf/syncope/blob/ba7f1a5c/client/console/src/main/resources/org/apache/syncope/client/console/panels/BeanReflectionModal.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/BeanReflectionModal.html b/client/console/src/main/resources/org/apache/syncope/client/console/panels/BeanReflectionModal.html
new file mode 100644
index 0000000..99693e7
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/BeanReflectionModal.html
@@ -0,0 +1,30 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+  <wicket:extend>
+    <form wicket:id="form">
+      <div class="bean">
+        <span wicket:id="bean">[Complex]</span>
+        <div class="modal-footer">
+          <input type="submit" class="btn btn-primary" wicket:id="apply"/>
+          <input type="button" class="btn btn-default" wicket:id="cancel"/>
+        </div>
+    </form>
+  </wicket:extend>
+</html>