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/13 12:44:35 UTC

[31/51] [partial] syncope git commit: [SYNCOPE-620] Re-organization completed

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
new file mode 100644
index 0000000..5cffe09
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
@@ -0,0 +1,184 @@
+/*
+ * 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.rest;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response;
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.common.lib.mod.RoleMod;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.RoleTO;
+import org.apache.syncope.common.lib.types.ResourceAssociationActionType;
+import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.common.lib.wrap.ResourceName;
+import org.apache.syncope.common.rest.api.CollectionWrapper;
+import org.apache.syncope.common.rest.api.service.ResourceService;
+import org.apache.syncope.common.rest.api.service.RoleService;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.springframework.stereotype.Component;
+
+/**
+ * Console client for invoking Rest Role's services.
+ */
+@Component
+public class RoleRestClient extends AbstractSubjectRestClient {
+
+    private static final long serialVersionUID = -8549081557283519638L;
+
+    @Override
+    public int count() {
+        return getService(RoleService.class).list(1, 1).getTotalCount();
+    }
+
+    public List<RoleTO> list() {
+        return getService(RoleService.class).list(1, 1000).getResult();
+    }
+
+    @Override
+    public List<RoleTO> list(final int page, final int size, final SortParam<String> sort) {
+        return getService(RoleService.class).list(page, size, toOrderBy(sort)).getResult();
+    }
+
+    @Override
+    public int searchCount(final String fiql) {
+        return getService(RoleService.class).search(fiql, 1, 1).getTotalCount();
+    }
+
+    @Override
+    public List<RoleTO> search(final String fiql, final int page, final int size, final SortParam<String> sort) {
+        return getService(RoleService.class).search(fiql, page, size, toOrderBy(sort)).getResult();
+    }
+
+    @Override
+    public ConnObjectTO getConnectorObject(final String resourceName, final Long id) {
+        return getService(ResourceService.class).getConnectorObject(resourceName, SubjectType.ROLE, id);
+    }
+
+    public RoleTO create(final RoleTO roleTO) {
+        Response response = getService(RoleService.class).create(roleTO);
+        return response.readEntity(RoleTO.class);
+    }
+
+    public RoleTO read(final Long id) {
+        return getAnonymousService(RoleService.class).read(id);
+    }
+
+    public RoleTO update(final String etag, final RoleMod roleMod) {
+        RoleTO result;
+        synchronized (this) {
+            RoleService service = getService(etag, RoleService.class);
+            result = service.update(roleMod.getKey(), roleMod).readEntity(RoleTO.class);
+            resetClient(RoleService.class);
+        }
+        return result;
+    }
+
+    @Override
+    public RoleTO delete(final String etag, final Long id) {
+        RoleTO result;
+        synchronized (this) {
+            RoleService service = getService(etag, RoleService.class);
+            result = service.delete(id).readEntity(RoleTO.class);
+            resetClient(RoleService.class);
+        }
+        return result;
+    }
+
+    @Override
+    public BulkActionResult bulkAction(final BulkAction action) {
+        return getService(RoleService.class).bulk(action);
+    }
+
+    public void unlink(final String etag, final long roleId, final List<StatusBean> statuses) {
+        synchronized (this) {
+            RoleService service = getService(etag, RoleService.class);
+            service.bulkDeassociation(roleId, ResourceDeassociationActionType.UNLINK,
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class));
+            resetClient(RoleService.class);
+        }
+    }
+
+    public void link(final String etag, final long roleId, final List<StatusBean> statuses) {
+        synchronized (this) {
+            RoleService service = getService(etag, RoleService.class);
+            service.bulkAssociation(roleId, ResourceAssociationActionType.LINK,
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class));
+            resetClient(RoleService.class);
+        }
+    }
+
+    public BulkActionResult deprovision(final String etag, final long roleId, final List<StatusBean> statuses) {
+        BulkActionResult result;
+        synchronized (this) {
+            RoleService service = getService(etag, RoleService.class);
+            result = service.bulkDeassociation(roleId, ResourceDeassociationActionType.DEPROVISION,
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class)).
+                    readEntity(BulkActionResult.class);
+            resetClient(RoleService.class);
+        }
+        return result;
+    }
+
+    public BulkActionResult provision(final String etag, final long roleId, final List<StatusBean> statuses) {
+        BulkActionResult result;
+        synchronized (this) {
+            RoleService service = getService(etag, RoleService.class);
+            result = service.bulkAssociation(roleId, ResourceAssociationActionType.PROVISION,
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class)).
+                    readEntity(BulkActionResult.class);
+            resetClient(RoleService.class);
+        }
+        return result;
+    }
+
+    public BulkActionResult unassign(final String etag, final long roleId, final List<StatusBean> statuses) {
+        BulkActionResult result;
+        synchronized (this) {
+            RoleService service = getService(etag, RoleService.class);
+            result = service.bulkDeassociation(roleId, ResourceDeassociationActionType.UNASSIGN,
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class)).
+                    readEntity(BulkActionResult.class);
+            resetClient(RoleService.class);
+        }
+        return result;
+    }
+
+    public BulkActionResult assign(final String etag, final long roleId, final List<StatusBean> statuses) {
+        BulkActionResult result;
+        synchronized (this) {
+            RoleService service = getService(etag, RoleService.class);
+            result = service.bulkAssociation(roleId, ResourceAssociationActionType.ASSIGN,
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class)).
+                    readEntity(BulkActionResult.class);
+            resetClient(RoleService.class);
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
new file mode 100644
index 0000000..378f98d
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
@@ -0,0 +1,250 @@
+/*
+ * 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.rest;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+import org.apache.syncope.client.console.SyncopeSession;
+import org.apache.syncope.client.console.commons.AttrLayoutType;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractSchemaTO;
+import org.apache.syncope.common.lib.to.DerSchemaTO;
+import org.apache.syncope.common.lib.to.PlainSchemaTO;
+import org.apache.syncope.common.lib.to.VirSchemaTO;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.syncope.common.rest.api.service.SchemaService;
+import org.springframework.stereotype.Component;
+
+/**
+ * Console client for invoking rest schema services.
+ */
+@Component
+public class SchemaRestClient extends BaseRestClient {
+
+    private static final long serialVersionUID = -2479730152700312373L;
+
+    public void filter(
+            final List<? extends AbstractSchemaTO> schemaTOs, final Collection<String> allowed, final boolean exclude) {
+
+        for (ListIterator<? extends AbstractSchemaTO> itor = schemaTOs.listIterator(); itor.hasNext();) {
+            AbstractSchemaTO schema = itor.next();
+            if (exclude) {
+                if (!allowed.contains(schema.getKey())) {
+                    itor.remove();
+                }
+            } else {
+                if (allowed.contains(schema.getKey())) {
+                    itor.remove();
+                }
+            }
+        }
+    }
+
+    public List<? extends AbstractSchemaTO> getSchemas(final AttributableType attrType, final SchemaType schemaType) {
+        List<? extends AbstractSchemaTO> schemas = Collections.emptyList();
+
+        try {
+            schemas = getService(SchemaService.class).list(attrType, schemaType);
+        } catch (SyncopeClientException e) {
+            LOG.error("While getting all schemas for {} and {}", attrType, schemaType, e);
+        }
+
+        if (attrType == AttributableType.CONFIGURATION) {
+            filter(schemas, AttrLayoutType.confKeys(), false);
+        }
+
+        return schemas;
+    }
+
+    public List<PlainSchemaTO> getSchemas(final AttributableType type) {
+        List<PlainSchemaTO> schemas = null;
+
+        try {
+            schemas = getService(SchemaService.class).list(type, SchemaType.PLAIN);
+        } catch (SyncopeClientException e) {
+            LOG.error("While getting all schemas", e);
+        }
+
+        return schemas;
+    }
+
+    public List<String> getSchemaNames(final AttributableType attrType, final SchemaType schemaType) {
+        final List<String> schemaNames = new ArrayList<>();
+
+        try {
+            final List<? extends AbstractSchemaTO> schemas = getSchemas(attrType, schemaType);
+            for (AbstractSchemaTO schemaTO : schemas) {
+                schemaNames.add(schemaTO.getKey());
+            }
+        } catch (SyncopeClientException e) {
+            LOG.error("While getting all user schema names", e);
+        }
+
+        return schemaNames;
+    }
+
+    public List<String> getPlainSchemaNames(final AttributableType type) {
+        final List<String> schemaNames = new ArrayList<>();
+
+        try {
+            final List<PlainSchemaTO> schemas = getSchemas(type);
+            for (PlainSchemaTO schemaTO : schemas) {
+                schemaNames.add(schemaTO.getKey());
+            }
+        } catch (SyncopeClientException e) {
+            LOG.error("While getting all user schema names", e);
+        }
+
+        return schemaNames;
+    }
+
+    public List<DerSchemaTO> getDerSchemas(final AttributableType type) {
+        List<DerSchemaTO> userDerSchemas = null;
+
+        try {
+            userDerSchemas = getService(SchemaService.class).list(type, SchemaType.DERIVED);
+        } catch (SyncopeClientException e) {
+            LOG.error("While getting all user derived schemas", e);
+        }
+
+        return userDerSchemas;
+    }
+
+    public List<String> getDerSchemaNames(final AttributableType type) {
+        final List<String> userDerSchemasNames = new ArrayList<>();
+
+        try {
+            final List<DerSchemaTO> userDerSchemas = getService(SchemaService.class).list(type, SchemaType.DERIVED);
+
+            for (DerSchemaTO schemaTO : userDerSchemas) {
+                userDerSchemasNames.add(schemaTO.getKey());
+            }
+        } catch (SyncopeClientException e) {
+            LOG.error("While getting all {} derived schema names", type, e);
+        }
+
+        return userDerSchemasNames;
+    }
+
+    public List<VirSchemaTO> getVirSchemas(final AttributableType type) {
+        List<VirSchemaTO> userVirSchemas = null;
+
+        try {
+            userVirSchemas = getService(SchemaService.class).list(type, SchemaType.VIRTUAL);
+        } catch (SyncopeClientException e) {
+            LOG.error("While getting all {} virtual schemas", type, e);
+        }
+
+        return userVirSchemas;
+    }
+
+    public List<String> getVirSchemaNames(final AttributableType type) {
+        final List<String> userVirSchemasNames = new ArrayList<String>();
+
+        try {
+            @SuppressWarnings("unchecked")
+            final List<VirSchemaTO> userVirSchemas = getService(SchemaService.class).list(type, SchemaType.VIRTUAL);
+            for (VirSchemaTO schemaTO : userVirSchemas) {
+                userVirSchemasNames.add(schemaTO.getKey());
+            }
+        } catch (SyncopeClientException e) {
+            LOG.error("While getting all user derived schema names", e);
+        }
+
+        return userVirSchemasNames;
+    }
+
+    public void createPlainSchema(final AttributableType type, final PlainSchemaTO schemaTO) {
+        getService(SchemaService.class).create(type, SchemaType.PLAIN, schemaTO);
+    }
+
+    public PlainSchemaTO readPlainSchema(final AttributableType type, final String name) {
+        PlainSchemaTO schema = null;
+
+        try {
+            schema = getService(SchemaService.class).read(type, SchemaType.PLAIN, name);
+        } catch (SyncopeClientException e) {
+            LOG.error("While reading a user schema", e);
+        }
+        return schema;
+    }
+
+    public void updatePlainSchema(final AttributableType type, final PlainSchemaTO schemaTO) {
+        getService(SchemaService.class).update(type, SchemaType.PLAIN, schemaTO.getKey(), schemaTO);
+    }
+
+    public PlainSchemaTO deletePlainSchema(final AttributableType type, final String name) {
+        PlainSchemaTO response = getService(SchemaService.class).read(type, SchemaType.PLAIN, name);
+        getService(SchemaService.class).delete(type, SchemaType.PLAIN, name);
+        return response;
+    }
+
+    public void createDerSchema(final AttributableType type, final DerSchemaTO schemaTO) {
+        getService(SchemaService.class).create(type, SchemaType.DERIVED, schemaTO);
+    }
+
+    public DerSchemaTO readDerSchema(final AttributableType type, final String name) {
+        DerSchemaTO derivedSchemaTO = null;
+        try {
+            derivedSchemaTO = getService(SchemaService.class).read(type, SchemaType.DERIVED, name);
+        } catch (SyncopeClientException e) {
+            LOG.error("While reading a derived user schema", e);
+        }
+        return derivedSchemaTO;
+    }
+
+    public void updateVirSchema(final AttributableType type, final VirSchemaTO schemaTO) {
+        getService(SchemaService.class).update(type, SchemaType.VIRTUAL, schemaTO.getKey(), schemaTO);
+    }
+
+    public DerSchemaTO deleteDerSchema(final AttributableType type, final String name) {
+        DerSchemaTO schemaTO = getService(SchemaService.class).read(type, SchemaType.DERIVED, name);
+        getService(SchemaService.class).delete(type, SchemaType.DERIVED, name);
+        return schemaTO;
+    }
+
+    public void createVirSchema(final AttributableType type, final VirSchemaTO schemaTO) {
+        getService(SchemaService.class).create(type, SchemaType.VIRTUAL, schemaTO);
+    }
+
+    public void updateDerSchema(final AttributableType type, final DerSchemaTO schemaTO) {
+        getService(SchemaService.class).update(type, SchemaType.DERIVED, schemaTO.getKey(), schemaTO);
+    }
+
+    public VirSchemaTO deleteVirSchema(final AttributableType type, final String name) {
+        VirSchemaTO schemaTO = getService(SchemaService.class).read(type, SchemaType.VIRTUAL, name);
+        getService(SchemaService.class).delete(type, SchemaType.VIRTUAL, name);
+        return schemaTO;
+    }
+
+    public List<String> getAllValidatorClasses() {
+        List<String> response = null;
+
+        try {
+            response = SyncopeSession.get().getSyncopeTO().getValidators();
+        } catch (SyncopeClientException e) {
+            LOG.error("While getting all validators", e);
+        }
+        return response;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/rest/SecurityQuestionRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/SecurityQuestionRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/SecurityQuestionRestClient.java
new file mode 100644
index 0000000..119b3b5
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/SecurityQuestionRestClient.java
@@ -0,0 +1,51 @@
+/*
+ * 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.rest;
+
+import java.util.List;
+import org.apache.syncope.common.lib.to.SecurityQuestionTO;
+import org.apache.syncope.common.rest.api.service.SecurityQuestionService;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SecurityQuestionRestClient extends BaseRestClient {
+
+    private static final long serialVersionUID = -3167730221361895176L;
+
+    public List<SecurityQuestionTO> list() {
+        return getService(SecurityQuestionService.class).list();
+    }
+
+    public void create(final SecurityQuestionTO securityQuestionTO) {
+        getService(SecurityQuestionService.class).create(securityQuestionTO);
+    }
+
+    public void update(final SecurityQuestionTO securityQuestionTO) {
+        getService(SecurityQuestionService.class).update(securityQuestionTO.getKey(), securityQuestionTO);
+    }
+
+    public void delete(final Long securityQuestionId) {
+        getService(SecurityQuestionService.class).delete(securityQuestionId);
+    }
+
+    public SecurityQuestionTO readByUser(final String username) {
+        return getService(SecurityQuestionService.class).readByUser(username);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
new file mode 100644
index 0000000..541b5cd
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
@@ -0,0 +1,139 @@
+/*
+ * 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.rest;
+
+import java.util.List;
+import org.apache.syncope.client.console.SyncopeSession;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.NotificationTaskTO;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.syncope.common.lib.to.PushTaskTO;
+import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.to.SyncTaskTO;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.common.rest.api.service.TaskService;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.springframework.stereotype.Component;
+
+/**
+ * Console client for invoking Rest Tasks services.
+ */
+@Component
+public class TaskRestClient extends BaseRestClient implements ExecutionRestClient {
+
+    private static final long serialVersionUID = 6284485820911028843L;
+
+    public List<String> getJobClasses() {
+        return SyncopeSession.get().getSyncopeTO().getTaskJobs();
+    }
+
+    public List<String> getSyncActionsClasses() {
+        return SyncopeSession.get().getSyncopeTO().getSyncActions();
+    }
+
+    public List<String> getPushActionsClasses() {
+        return SyncopeSession.get().getSyncopeTO().getPushActions();
+    }
+
+    /**
+     * Return the number of tasks.
+     *
+     * @param kind of task (propagation, sched, sync).
+     * @return number of stored tasks.
+     */
+    public int count(final String kind) {
+        return getService(TaskService.class).list(TaskType.fromString(kind), 1, 1).getTotalCount();
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends AbstractTaskTO> List<T> list(final Class<T> reference,
+            final int page, final int size, final SortParam<String> sort) {
+
+        return (List<T>) getService(TaskService.class).list(getTaskType(reference), page, size, toOrderBy(sort)).
+                getResult();
+    }
+
+    private TaskType getTaskType(final Class<?> reference) {
+        TaskType result = null;
+        if (PropagationTaskTO.class.equals(reference)) {
+            result = TaskType.PROPAGATION;
+        } else if (NotificationTaskTO.class.equals(reference)) {
+            result = TaskType.NOTIFICATION;
+        } else if (SchedTaskTO.class.equals(reference)) {
+            result = TaskType.SCHEDULED;
+        } else if (SyncTaskTO.class.equals(reference)) {
+            result = TaskType.SYNCHRONIZATION;
+        } else if (PushTaskTO.class.equals(reference)) {
+            result = TaskType.PUSH;
+        }
+        return result;
+    }
+
+    public PropagationTaskTO readPropagationTask(final Long taskId) {
+        return getService(TaskService.class).read(taskId);
+    }
+
+    public NotificationTaskTO readNotificationTask(final Long taskId) {
+        return getService(TaskService.class).read(taskId);
+    }
+
+    public <T extends SchedTaskTO> T readSchedTask(final Class<T> reference, final Long taskId) {
+        return getService(TaskService.class).read(taskId);
+    }
+
+    public void delete(final Long taskId, final Class<? extends AbstractTaskTO> taskToClass) {
+        getService(TaskService.class).delete(taskId);
+    }
+
+    @Override
+    public void startExecution(final long taskId) {
+        startExecution(taskId, false);
+    }
+
+    public void startExecution(final long taskId, final boolean dryRun) {
+        getService(TaskService.class).execute(taskId, dryRun);
+    }
+
+    @Override
+    public void deleteExecution(final long taskExecId) {
+        getService(TaskService.class).deleteExecution(taskExecId);
+    }
+
+    public void createSyncTask(final SyncTaskTO taskTO) {
+        getService(TaskService.class).create(taskTO);
+    }
+
+    public void createSchedTask(final SchedTaskTO taskTO) {
+        getService(TaskService.class).create(taskTO);
+    }
+
+    public void updateSchedTask(final SchedTaskTO taskTO) {
+        getService(TaskService.class).update(taskTO.getKey(), taskTO);
+    }
+
+    public void updateSyncTask(final SyncTaskTO taskTO) {
+        getService(TaskService.class).update(taskTO.getKey(), taskTO);
+    }
+
+    public BulkActionResult bulkAction(final BulkAction action) {
+        return getService(TaskService.class).bulk(action);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
new file mode 100644
index 0000000..bca0e28
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java
@@ -0,0 +1,228 @@
+/*
+ * 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.rest;
+
+import java.util.List;
+import javax.ws.rs.core.Response;
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.ResourceAssociationMod;
+import org.apache.syncope.common.lib.mod.StatusMod;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.BulkAction;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.ConnObjectTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ResourceAssociationActionType;
+import org.apache.syncope.common.lib.types.ResourceDeassociationActionType;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.common.lib.wrap.ResourceName;
+import org.apache.syncope.common.rest.api.CollectionWrapper;
+import org.apache.syncope.common.rest.api.service.ResourceService;
+import org.apache.syncope.common.rest.api.service.UserService;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.springframework.stereotype.Component;
+
+/**
+ * Console client for invoking rest users services.
+ */
+@Component
+public class UserRestClient extends AbstractSubjectRestClient {
+
+    private static final long serialVersionUID = -1575748964398293968L;
+
+    @Override
+    public int count() {
+        return getService(UserService.class).list(1, 1).getTotalCount();
+    }
+
+    @Override
+    public List<UserTO> list(final int page, final int size, final SortParam<String> sort) {
+        return getService(UserService.class).list(page, size, toOrderBy(sort)).getResult();
+    }
+
+    public UserTO create(final UserTO userTO, final boolean storePassword) {
+        Response response = getService(UserService.class).create(userTO, storePassword);
+        return response.readEntity(UserTO.class);
+    }
+
+    public UserTO update(final String etag, final UserMod userMod) {
+        UserTO result;
+        synchronized (this) {
+            UserService service = getService(etag, UserService.class);
+            result = service.update(userMod.getKey(), userMod).readEntity(UserTO.class);
+            resetClient(UserService.class);
+        }
+        return result;
+    }
+
+    @Override
+    public UserTO delete(final String etag, final Long id) {
+        UserTO result;
+        synchronized (this) {
+            UserService service = getService(etag, UserService.class);
+            result = service.delete(id).readEntity(UserTO.class);
+            resetClient(UserService.class);
+        }
+        return result;
+    }
+
+    public UserTO read(final Long id) {
+        UserTO userTO = null;
+        try {
+            userTO = getService(UserService.class).read(id);
+        } catch (SyncopeClientException e) {
+            LOG.error("While reading a user", e);
+        }
+        return userTO;
+    }
+
+    @Override
+    public int searchCount(final String fiql) {
+        return getService(UserService.class).search(fiql, 1, 1).getTotalCount();
+    }
+
+    @Override
+    public List<UserTO> search(final String fiql, final int page, final int size, final SortParam<String> sort) {
+        return getService(UserService.class).search(fiql, page, size, toOrderBy(sort)).getResult();
+    }
+
+    @Override
+    public ConnObjectTO getConnectorObject(final String resourceName, final Long id) {
+        return getService(ResourceService.class).getConnectorObject(resourceName, SubjectType.USER, id);
+    }
+
+    public void suspend(final String etag, final long userId, final List<StatusBean> statuses) {
+        StatusMod statusMod = StatusUtils.buildStatusMod(statuses, false);
+        statusMod.setType(StatusMod.ModType.SUSPEND);
+        synchronized (this) {
+            UserService service = getService(etag, UserService.class);
+            service.status(userId, statusMod);
+            resetClient(UserService.class);
+        }
+    }
+
+    public void reactivate(final String etag, final long userId, final List<StatusBean> statuses) {
+        StatusMod statusMod = StatusUtils.buildStatusMod(statuses, true);
+        statusMod.setType(StatusMod.ModType.REACTIVATE);
+        synchronized (this) {
+            UserService service = getService(etag, UserService.class);
+            service.status(userId, statusMod);
+            resetClient(UserService.class);
+        }
+    }
+
+    @Override
+    public BulkActionResult bulkAction(final BulkAction action) {
+        return getService(UserService.class).bulk(action);
+    }
+
+    public void unlink(final String etag, final long userId, final List<StatusBean> statuses) {
+        synchronized (this) {
+            UserService service = getService(etag, UserService.class);
+            service.bulkDeassociation(userId, ResourceDeassociationActionType.UNLINK,
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class));
+            resetClient(UserService.class);
+        }
+    }
+
+    public void link(final String etag, final long userId, final List<StatusBean> statuses) {
+        synchronized (this) {
+            UserService service = getService(etag, UserService.class);
+
+            final ResourceAssociationMod associationMod = new ResourceAssociationMod();
+            associationMod.getTargetResources().addAll(
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class));
+            service.bulkAssociation(userId, ResourceAssociationActionType.LINK, associationMod);
+
+            resetClient(UserService.class);
+        }
+    }
+
+    public BulkActionResult deprovision(final String etag, final long userId, final List<StatusBean> statuses) {
+        BulkActionResult result;
+        synchronized (this) {
+            UserService service = getService(etag, UserService.class);
+            result = service.bulkDeassociation(userId, ResourceDeassociationActionType.DEPROVISION,
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class)).
+                    readEntity(BulkActionResult.class);
+            resetClient(UserService.class);
+        }
+        return result;
+    }
+
+    public BulkActionResult provision(final String etag, final long userId,
+            final List<StatusBean> statuses, final boolean changepwd, final String password) {
+
+        BulkActionResult result;
+        synchronized (this) {
+            UserService service = getService(etag, UserService.class);
+
+            final ResourceAssociationMod associationMod = new ResourceAssociationMod();
+            associationMod.getTargetResources().addAll(
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class));
+            associationMod.setChangePwd(changepwd);
+            associationMod.setPassword(password);
+
+            result = service.bulkAssociation(userId, ResourceAssociationActionType.PROVISION, associationMod).
+                    readEntity(BulkActionResult.class);
+            resetClient(UserService.class);
+        }
+        return result;
+    }
+
+    public BulkActionResult unassign(final String etag, final long userId, final List<StatusBean> statuses) {
+        BulkActionResult result;
+        synchronized (this) {
+            UserService service = getService(etag, UserService.class);
+            result = service.bulkDeassociation(userId, ResourceDeassociationActionType.UNASSIGN,
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class)).
+                    readEntity(BulkActionResult.class);
+            resetClient(UserService.class);
+        }
+        return result;
+    }
+
+    public BulkActionResult assign(final String etag, final long userId,
+            final List<StatusBean> statuses, final boolean changepwd, final String password) {
+
+        BulkActionResult result;
+        synchronized (this) {
+            UserService service = getService(etag, UserService.class);
+
+            final ResourceAssociationMod associationMod = new ResourceAssociationMod();
+            associationMod.getTargetResources().addAll(
+                    CollectionWrapper.wrap(StatusUtils.buildStatusMod(statuses).getResourceNames(),
+                            ResourceName.class));
+            associationMod.setChangePwd(changepwd);
+            associationMod.setPassword(password);
+
+            result = service.bulkAssociation(userId, ResourceAssociationActionType.ASSIGN, associationMod).
+                    readEntity(BulkActionResult.class);
+            resetClient(UserService.class);
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/rest/UserSelfRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/UserSelfRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserSelfRestClient.java
new file mode 100644
index 0000000..1bb1079
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserSelfRestClient.java
@@ -0,0 +1,96 @@
+/*
+ * 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.rest;
+
+import org.apache.syncope.client.console.SyncopeSession;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.mod.UserMod;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.rest.api.service.UserSelfService;
+import org.springframework.stereotype.Component;
+
+@Component
+public class UserSelfRestClient extends BaseRestClient {
+
+    private static final long serialVersionUID = 2994691796924731295L;
+
+    public boolean isSelfRegistrationAllowed() {
+        Boolean result = null;
+        try {
+            result = SyncopeSession.get().getSyncopeTO().isSelfRegAllowed();
+        } catch (SyncopeClientException e) {
+            LOG.error("While seeking if self registration is allowed", e);
+        }
+
+        return result == null
+                ? false
+                : result.booleanValue();
+    }
+
+    public UserTO read() {
+        return getService(UserSelfService.class).read();
+    }
+
+    public void create(final UserTO userTO, final boolean storePassword) {
+        getService(UserSelfService.class).create(userTO, storePassword);
+    }
+
+    public void update(final UserMod userMod) {
+        getService(UserSelfService.class).update(userMod.getKey(), userMod);
+    }
+
+    public void delete() {
+        getService(UserSelfService.class).delete();
+    }
+
+    public boolean isPasswordResetAllowed() {
+        Boolean result = null;
+        try {
+            result = SyncopeSession.get().getSyncopeTO().isPwdResetAllowed();
+        } catch (SyncopeClientException e) {
+            LOG.error("While seeking if password reset is allowed", e);
+        }
+
+        return result == null
+                ? false
+                : result.booleanValue();
+    }
+
+    public boolean isPwdResetRequiringSecurityQuestions() {
+        Boolean result = null;
+        try {
+            result = SyncopeSession.get().getSyncopeTO().isPwdResetRequiringSecurityQuestions();
+        } catch (SyncopeClientException e) {
+            LOG.error("While seeking if password reset requires security question", e);
+        }
+
+        return result == null
+                ? false
+                : result.booleanValue();
+    }
+
+    public void requestPasswordReset(final String username, final String securityAnswer) {
+        getService(UserSelfService.class).requestPasswordReset(username, securityAnswer);
+    }
+
+    public void confirmPasswordReset(final String token, final String password) {
+        getService(UserSelfService.class).confirmPasswordReset(token, password);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/rest/WorkflowRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/WorkflowRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/WorkflowRestClient.java
new file mode 100644
index 0000000..f3bf60c
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/WorkflowRestClient.java
@@ -0,0 +1,69 @@
+/*
+ * 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.rest;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.syncope.client.console.SyncopeSession;
+import org.apache.syncope.common.lib.types.SubjectType;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.WorkflowService;
+import org.springframework.stereotype.Component;
+
+@Component
+public class WorkflowRestClient extends BaseRestClient {
+
+    private static final long serialVersionUID = 5049285686167071017L;
+
+    private WorkflowService getService(final MediaType mediaType) {
+        return SyncopeSession.get().getService(mediaType, WorkflowService.class);
+    }
+
+    public InputStream getDefinition(final MediaType mediaType) {
+        Response response = getService(mediaType).exportDefinition(SubjectType.USER);
+
+        return (InputStream) response.getEntity();
+    }
+
+    public byte[] getDiagram() {
+        WorkflowService service = getService(WorkflowService.class);
+        WebClient.client(service).accept(RESTHeaders.MEDIATYPE_IMAGE_PNG);
+        Response response = service.exportDiagram(SubjectType.USER);
+
+        byte[] diagram;
+        try {
+            diagram = IOUtils.readBytesFromStream((InputStream) response.getEntity());
+        } catch (Exception e) {
+            LOG.error("Could not get workflow diagram", e);
+            diagram = new byte[0];
+        }
+        return diagram;
+    }
+
+    public boolean isActivitiEnabledForUsers() {
+        return SyncopeSession.get().getSyncopeTO().getUserWorkflowAdapter().indexOf("Activiti") != -1;
+    }
+
+    public void updateDefinition(final MediaType mediaType, final String definition) {
+        getService(mediaType).importDefinition(SubjectType.USER, definition);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/AbstractAjaxDownloadBehavior.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/AbstractAjaxDownloadBehavior.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/AbstractAjaxDownloadBehavior.java
new file mode 100644
index 0000000..8074d37
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/form/AbstractAjaxDownloadBehavior.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.ajax.form;
+
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.behavior.AbstractAjaxBehavior;
+import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
+import org.apache.wicket.util.resource.IResourceStream;
+
+public abstract class AbstractAjaxDownloadBehavior extends AbstractAjaxBehavior {
+
+    private static final long serialVersionUID = 6833760760338614245L;
+
+    /**
+     * Call this method to initiate the download.
+     */
+    public void initiate(final AjaxRequestTarget target) {
+        CharSequence url = getCallbackUrl();
+
+        target.appendJavaScript("window.location.href='" + url + "'");
+    }
+
+    @Override
+    public void onRequest() {
+        getComponent().getRequestCycle().scheduleRequestHandlerAfterCurrent(
+                new ResourceStreamRequestHandler(getResourceStream(), getFileName()));
+    }
+
+    protected abstract String getFileName();
+
+    protected abstract IResourceStream getResourceStream();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxButton.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxButton.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxButton.java
new file mode 100644
index 0000000..314f66c
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxButton.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.ajax.markup.html;
+
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.IModel;
+
+public abstract class ClearIndicatingAjaxButton extends IndicatingAjaxButton {
+
+    private static final long serialVersionUID = 7206379812788748287L;
+
+    private final PageReference pageRef;
+
+    private boolean reloadFeebackPanel = true;
+
+    public ClearIndicatingAjaxButton(final String id, final PageReference pageRef) {
+        super(id);
+        this.pageRef = pageRef;
+    }
+
+    public ClearIndicatingAjaxButton(final String id, Form<?> form, final PageReference pageRef) {
+        super(id, form);
+        this.pageRef = pageRef;
+    }
+
+    public ClearIndicatingAjaxButton(final String id, IModel<String> model, final PageReference pageRef) {
+        super(id, model);
+        this.pageRef = pageRef;
+    }
+
+    public ClearIndicatingAjaxButton(final String id, final IModel<String> model, final Form<?> form,
+            final PageReference pageRef) {
+
+        super(id, model, form);
+        this.pageRef = pageRef;
+    }
+
+    protected abstract void onSubmitInternal(AjaxRequestTarget target, Form<?> form);
+
+    public ClearIndicatingAjaxButton feedbackPanelAutomaticReload(boolean reloadFeedbackPanel) {
+        this.reloadFeebackPanel = reloadFeedbackPanel;
+        return this;
+    }
+
+    @Override
+    protected final void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+        super.onSubmit(target, form);
+
+        Page page = pageRef.getPage();
+        if (reloadFeebackPanel && page instanceof BasePage) {
+            target.add(((BasePage) page).getFeedbackPanel());
+        }
+        onSubmitInternal(target, form);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxLink.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxLink.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxLink.java
new file mode 100644
index 0000000..5bb5642
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/ClearIndicatingAjaxLink.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.ajax.markup.html;
+
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink;
+import org.apache.wicket.model.IModel;
+
+public abstract class ClearIndicatingAjaxLink<T> extends IndicatingAjaxLink<T> {
+
+    private static final long serialVersionUID = 7913625094362339643L;
+
+    private final PageReference pageRef;
+
+    private boolean reloadFeedbackPanel = true;
+
+    public ClearIndicatingAjaxLink(final String id, final PageReference pageRef) {
+        super(id);
+        this.pageRef = pageRef;
+    }
+
+    public ClearIndicatingAjaxLink(final String id, final IModel<T> model, final PageReference pageRef) {
+        super(id, model);
+        this.pageRef = pageRef;
+    }
+
+    public ClearIndicatingAjaxLink<T> feedbackPanelAutomaticReload(boolean reloadFeedbackPanel) {
+        this.reloadFeedbackPanel = reloadFeedbackPanel;
+        return this;
+    }
+
+    protected abstract void onClickInternal(AjaxRequestTarget target);
+
+    @Override
+    public final void onClick(final AjaxRequestTarget target) {
+        Page page = pageRef.getPage();
+        if (reloadFeedbackPanel && page instanceof BasePage) {
+            target.add(((BasePage) page).getFeedbackPanel());
+        }
+        onClickInternal(target);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/IndicatingOnConfirmAjaxLink.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/IndicatingOnConfirmAjaxLink.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/IndicatingOnConfirmAjaxLink.java
new file mode 100644
index 0000000..86db915
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/ajax/markup/html/IndicatingOnConfirmAjaxLink.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.ajax.markup.html;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.attributes.AjaxCallListener;
+import org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
+
+public abstract class IndicatingOnConfirmAjaxLink<T> extends ClearIndicatingAjaxLink<T> {
+
+    private static final long serialVersionUID = 2228670850922265663L;
+
+    private final String msg;
+
+    public IndicatingOnConfirmAjaxLink(final String id, final PageReference pageRef) {
+        this(id, pageRef, "confirmDelete");
+    }
+
+    public IndicatingOnConfirmAjaxLink(final String id, final PageReference pageRef, final String msg) {
+        super(id, pageRef);
+        this.msg = msg;
+    }
+
+    @Override
+    protected void updateAjaxAttributes(final AjaxRequestAttributes attributes) {
+        super.updateAjaxAttributes(attributes);
+
+        final AjaxCallListener ajaxCallListener = new AjaxCallListener() {
+
+            private static final long serialVersionUID = 7160235486520935153L;
+
+            @Override
+            public CharSequence getPrecondition(final Component component) {
+                return "if (!confirm('"
+                        + getString(IndicatingOnConfirmAjaxLink.this.msg)
+                        + "')) {return false;} else {return true;}";
+            }
+        };
+        attributes.getAjaxCallListeners().add(ajaxCallListener);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionColumn.java
new file mode 100644
index 0000000..b9dfa62
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionColumn.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.wicket.Component;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class ActionColumn<T, S> extends AbstractColumn<T, S> {
+
+    private static final long serialVersionUID = 7955560320949560725L;
+
+    /**
+     * Logger.
+     */
+    protected static final Logger LOG = LoggerFactory.getLogger(ActionColumn.class);
+
+    public ActionColumn(final IModel<String> displayModel) {
+        super(displayModel);
+    }
+
+    @Override
+    public String getCssClass() {
+        return "action";
+    }
+
+    @Override
+    public Component getHeader(final String componentId) {
+        return super.getHeader(componentId);
+    }
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<T>> item, final String componentId, final IModel<T> rowModel) {
+        item.add(getActions(componentId, rowModel));
+    }
+
+    public abstract ActionLinksPanel getActions(final String componentId, final IModel<T> rowModel);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionResultColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionResultColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionResultColumn.java
new file mode 100644
index 0000000..a2c40ff
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/ActionResultColumn.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import java.beans.PropertyDescriptor;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.BulkActionResult.Status;
+import org.apache.wicket.Component;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+
+public class ActionResultColumn<T, S> extends AbstractColumn<T, S> {
+
+    private static final long serialVersionUID = 7955560320949560716L;
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = LoggerFactory.getLogger(ActionResultColumn.class);
+
+    private final BulkActionResult results;
+
+    private final String idFieldName;
+
+    public ActionResultColumn(final BulkActionResult results, final String idFieldName) {
+        super(new Model<String>());
+        this.results = results;
+        this.idFieldName = idFieldName;
+    }
+
+    @Override
+    public String getCssClass() {
+        return "bulkResultColumn";
+    }
+
+    @Override
+    public Component getHeader(final String componentId) {
+        return new Label(componentId, new ResourceModel("bulkActionResultLabel", "Result"));
+    }
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<T>> item, final String componentId, final IModel<T> rowModel) {
+        try {
+            final PropertyDescriptor propDesc =
+                    BeanUtils.getPropertyDescriptor(rowModel.getObject().getClass(), idFieldName);
+            final Object id = propDesc.getReadMethod().invoke(rowModel.getObject(), new Object[0]);
+            final Status status = id == null ? null : results.getResultMap().get(id.toString());
+            item.add(new Label(componentId, status == null ? Status.SUCCESS : status.toString()));
+        } catch (Exception e) {
+            LOG.error("Errore retrieving target id value", e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
new file mode 100644
index 0000000..b40d7c8
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/AttrColumn.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.List;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.types.SchemaType;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+
+public class AttrColumn extends AbstractColumn<AbstractAttributableTO, String> {
+
+    private static final long serialVersionUID = 2624734332447371372L;
+
+    private final String name;
+
+    private final SchemaType schemaType;
+
+    public AttrColumn(final String name, final SchemaType schemaType) {
+        // set sortProperty to schematype#name (e.g. derivedSchema#cn, 
+        // for use with SortableUserProviderComparator.AttrModel#getObject)
+        super(new ResourceModel(name, name), schemaType.name() + "#" + name);
+        this.name = name;
+        this.schemaType = schemaType;
+    }
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<AbstractAttributableTO>> cellItem, final String componentId,
+            final IModel<AbstractAttributableTO> rowModel) {
+
+        List<String> values = null;
+
+        switch (schemaType) {
+            case PLAIN:
+                if (rowModel.getObject().getPlainAttrMap().containsKey(name)) {
+                    values = rowModel.getObject().getPlainAttrMap().get(name).getValues();
+                }
+                break;
+
+            case VIRTUAL:
+                if (rowModel.getObject().getVirAttrMap().containsKey(name)) {
+                    values = rowModel.getObject().getVirAttrMap().get(name).getValues();
+                }
+                break;
+
+            case DERIVED:
+                if (rowModel.getObject().getDerAttrMap().containsKey(name)) {
+                    values = rowModel.getObject().getDerAttrMap().get(name).getValues();
+                }
+                break;
+
+            default:
+        }
+
+        if (values == null || values.isEmpty()) {
+            cellItem.add(new Label(componentId, ""));
+        } else {
+            if (values.size() == 1) {
+                cellItem.add(new Label(componentId, values.get(0)));
+            } else {
+                cellItem.add(new Label(componentId, values.toString()));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxGroupSelectorPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxGroupSelectorPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxGroupSelectorPanel.java
new file mode 100644
index 0000000..8f880b7
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxGroupSelectorPanel.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.wicket.markup.html.form.CheckGroup;
+import org.apache.wicket.markup.html.form.CheckGroupSelector;
+import org.apache.wicket.markup.html.panel.Panel;
+
+public class CheckBoxGroupSelectorPanel<T> extends Panel {
+
+    private static final long serialVersionUID = 4062106303929176865L;
+
+    public CheckBoxGroupSelectorPanel(final String componentId, final CheckGroup<T> group) {
+
+        super(componentId);
+        add(new CheckGroupSelector("groupselector", group));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxPanel.java
new file mode 100644
index 0000000..db87192
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxPanel.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.syncope.client.console.commons.ActionTableCheckGroup;
+import org.apache.wicket.markup.html.form.Check;
+import org.apache.wicket.markup.html.form.CheckGroup;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+
+public class CheckBoxPanel<T> extends Panel {
+
+    private static final long serialVersionUID = 4062106303929176865L;
+
+    private final Check<T> check;
+
+    public CheckBoxPanel(final String componentId, final IModel<T> model, final CheckGroup<T> checkGroup) {
+        super(componentId, model);
+        this.check = new Check<T>("check", model, checkGroup);
+        if (checkGroup instanceof ActionTableCheckGroup) {
+            boolean checkable = ((ActionTableCheckGroup<T>) checkGroup).isCheckable(model.getObject());
+            this.check.setEnabled(checkable);
+            this.check.setVisible(checkable);
+        }
+        add(this.check);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckGroupColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckGroupColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckGroupColumn.java
new file mode 100644
index 0000000..cf13f3c
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CheckGroupColumn.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.markup.html.form.CheckGroup;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+
+public class CheckGroupColumn<T, S> extends AbstractColumn<T, S> {
+
+    private static final long serialVersionUID = 7955560320949560715L;
+
+    private final CheckGroup<T> group;
+
+    public CheckGroupColumn(final CheckGroup<T> checkGroup) {
+        super(new Model<String>());
+        this.group = checkGroup;
+    }
+
+    @Override
+    public String getCssClass() {
+        return "checkGroupColumn";
+    }
+
+    @Override
+    public Component getHeader(final String componentId) {
+        return new CheckBoxGroupSelectorPanel<T>(componentId, group);
+    }
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<T>> item, final String componentId, final IModel<T> rowModel) {
+        item.add(new CheckBoxPanel<T>(componentId, rowModel, group));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CollectionPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CollectionPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CollectionPanel.java
new file mode 100644
index 0000000..f04fa5a
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CollectionPanel.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.List;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.ResourceModel;
+
+public class CollectionPanel extends Panel {
+
+    private static final long serialVersionUID = -4042497356836230377L;
+
+    @SuppressWarnings("unchecked")
+    public CollectionPanel(final String id, final List values) {
+        super(id);
+
+        add(new ListView("collection", values) {
+
+            private static final long serialVersionUID = 4949588177564901031L;
+
+            @Override
+            protected void populateItem(final ListItem item) {
+                final String value = item.getModelObject() == null ? null : item.getModelObject().toString();
+                item.add(new Label("item", new ResourceModel(value, value)));
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CollectionPropertyColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CollectionPropertyColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CollectionPropertyColumn.java
new file mode 100644
index 0000000..a5fd774
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/CollectionPropertyColumn.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+
+public class CollectionPropertyColumn<T> extends PropertyColumn<T, String> {
+
+    private static final long serialVersionUID = 8077865338230121496L;
+
+    public CollectionPropertyColumn(
+            final IModel<String> displayModel,
+            final String sortProperty,
+            final String propertyExpression) {
+        super(displayModel, sortProperty, propertyExpression);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void populateItem(
+            final Item<ICellPopulator<T>> cellItem, final String componentId, final IModel<T> rowModel) {
+
+        final Object value = getDataModel(rowModel).getObject();
+
+        if (value instanceof Collection) {
+            final List values = new ArrayList((Collection) value);
+            Collections.sort(values);
+            cellItem.add(new CollectionPanel(componentId, values));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/DatePropertyColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/DatePropertyColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/DatePropertyColumn.java
new file mode 100644
index 0000000..f767aa2
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/DatePropertyColumn.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import java.util.Date;
+import org.apache.syncope.client.console.SyncopeSession;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+
+/**
+ * Format column's value as date string.
+ */
+public class DatePropertyColumn<T> extends PropertyColumn<T, String> {
+
+    private static final long serialVersionUID = 3527840552172947705L;
+
+    public DatePropertyColumn(final IModel<String> displayModel, final String sortProperty,
+            final String propertyExpression) {
+
+        super(displayModel, sortProperty, propertyExpression);
+    }
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<T>> item, final String componentId, final IModel<T> rowModel) {
+
+        IModel<Object> date = getDataModel(rowModel);
+
+        String convertedDate = "";
+        if (date.getObject() instanceof Date) {
+            convertedDate = SyncopeSession.get().getDateFormat().format(date.getObject());
+        }
+        item.add(new Label(componentId, convertedDate));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/TokenColumn.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/TokenColumn.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/TokenColumn.java
new file mode 100644
index 0000000..094e450
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/extensions/markup/html/repeater/data/table/TokenColumn.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table;
+
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+import org.springframework.util.StringUtils;
+
+public class TokenColumn extends AbstractColumn<AbstractAttributableTO, String> {
+
+    private static final long serialVersionUID = 8077865338230121496L;
+
+    public TokenColumn(final String name) {
+        super(new ResourceModel(name, name), name);
+    }
+
+    @Override
+    public void populateItem(final Item<ICellPopulator<AbstractAttributableTO>> cellItem, final String componentId,
+            final IModel<AbstractAttributableTO> rowModel) {
+
+        if (rowModel.getObject() instanceof UserTO) {
+            if (StringUtils.hasText(((UserTO) rowModel.getObject()).getToken())) {
+                cellItem.add(new Label(componentId, new ResourceModel("tokenValued", "tokenValued")));
+            } else {
+                cellItem.add(new Label(componentId, new ResourceModel("tokenNotValued", "tokenNotValued")));
+            }
+        }
+    }
+}