You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2013/10/07 16:38:57 UTC

svn commit: r1529856 [1/3] - in /syncope/trunk: common/src/main/java/org/apache/syncope/common/services/ common/src/main/java/org/apache/syncope/common/to/ console/ console/src/main/java/org/apache/syncope/console/commons/ console/src/main/java/org/apa...

Author: fmartelli
Date: Mon Oct  7 14:38:55 2013
New Revision: 1529856

URL: http://svn.apache.org/r1529856
Log:
SYNCOPE-393 fixed

Added:
    syncope/trunk/common/src/main/java/org/apache/syncope/common/to/AttributableTargetsTO.java
      - copied, changed from r1525003, syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java
    syncope/trunk/common/src/main/java/org/apache/syncope/common/to/BulkAssociationAction.java
      - copied, changed from r1525003, syncope/trunk/common/src/main/java/org/apache/syncope/common/to/BulkAction.java
    syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationTargetsTO.java
      - copied, changed from r1525003, syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/ActionTableCheckGroup.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/AbstractStatusModlaPage.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ProvisioningModalPage.java
      - copied, changed from r1525003, syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/StatusModalPage.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/panels/ActionDataTablePanel.java
      - copied, changed from r1525003, syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/panels/AjaxDataTablePanel.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/panels/ImagePanel.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/wicket/ajax/markup/html/IndicatingOnConfirmAjaxLink.java
      - copied, changed from r1525003, syncope/trunk/console/src/main/java/org/apache/syncope/console/wicket/ajax/markup/html/IndicatingDeleteOnConfirmAjaxLink.java
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/AbstractStatusModlaPage.html
      - copied, changed from r1525003, syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/StatusModalPage.html
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/AbstractStatusModlaPage.properties
      - copied unchanged from r1525003, syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/StatusModalPage.properties
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/AbstractStatusModlaPage_it.properties
      - copied unchanged from r1525003, syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/StatusModalPage_it.properties
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/AbstractStatusModlaPage_pt_BR.properties
      - copied unchanged from r1525003, syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/StatusModalPage_pt_BR.properties
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/panels/ActionDataTablePanel.html
      - copied, changed from r1525003, syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/panels/AjaxDataTablePanel.html
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/panels/ImagePanel.html
      - copied, changed from r1525003, syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/panels/AbstractSearchPanel.html
    syncope/trunk/console/src/main/webapp/img/actions/deprovision-icon.png   (with props)
    syncope/trunk/console/src/main/webapp/img/actions/manage-icon.png   (with props)
    syncope/trunk/console/src/main/webapp/img/actions/resources-icon.png   (with props)
    syncope/trunk/console/src/main/webapp/img/actions/roles-icon.png   (with props)
    syncope/trunk/console/src/main/webapp/img/actions/unassign-icon.png   (with props)
    syncope/trunk/console/src/main/webapp/img/actions/unlink-icon.png   (with props)
    syncope/trunk/console/src/main/webapp/img/actions/users-icon.png   (with props)
Removed:
    syncope/trunk/console/src/main/java/org/apache/syncope/console/wicket/ajax/markup/html/IndicatingDeleteOnConfirmAjaxLink.java
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/StatusModalPage.html
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/StatusModalPage.properties
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/StatusModalPage_it.properties
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/StatusModalPage_pt_BR.properties
Modified:
    syncope/trunk/common/src/main/java/org/apache/syncope/common/services/ResourceService.java
    syncope/trunk/common/src/main/java/org/apache/syncope/common/services/RoleService.java
    syncope/trunk/common/src/main/java/org/apache/syncope/common/services/UserService.java
    syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java
    syncope/trunk/console/pom.xml
    syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/StatusBean.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/StatusUtils.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/AbstractBasePage.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ResourceModalPage.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/Resources.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ResultStatusModalPage.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/StatusModalPage.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/TaskModalPage.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/Tasks.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/VirtualSchemaModalPage.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/panels/AbstractSearchResultPanel.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/panels/MembershipsPanel.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/panels/ResourcesPanel.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/panels/RoleSearchResultPanel.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/panels/StatusPanel.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/panels/UserSearchResultPanel.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/rest/ResourceRestClient.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/rest/RoleRestClient.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/rest/UserRestClient.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/wicket/extensions/markup/html/repeater/data/table/CheckBoxPanel.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/wicket/markup/html/form/ActionLink.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/wicket/markup/html/form/ActionLinksPanel.java
    syncope/trunk/console/src/main/java/org/apache/syncope/console/wicket/markup/html/tree/TreeActionLinkPanel.java
    syncope/trunk/console/src/main/resources/authorizations.xml
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/SyncopeApplication.properties
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/SyncopeApplication_it.properties
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/SyncopeApplication_pt_BR.properties
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/pages/Resources.html
    syncope/trunk/console/src/main/resources/org/apache/syncope/console/wicket/markup/html/form/ActionLinksPanel.html
    syncope/trunk/console/src/test/java/org/apache/syncope/console/ConfigurationTestITCase.java
    syncope/trunk/console/src/test/java/org/apache/syncope/console/ConnInstanceTestITCase.java
    syncope/trunk/console/src/test/java/org/apache/syncope/console/ReportTestITCase.java
    syncope/trunk/console/src/test/java/org/apache/syncope/console/ResourceTestITCase.java
    syncope/trunk/console/src/test/java/org/apache/syncope/console/RoleTestITCase.java
    syncope/trunk/console/src/test/java/org/apache/syncope/console/SchemaTestITCase.java
    syncope/trunk/console/src/test/java/org/apache/syncope/console/TaskTestITCase.java
    syncope/trunk/console/src/test/java/org/apache/syncope/console/UserTestITCase.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/propagation/impl/PropagationManager.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/ResourceController.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/RoleController.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/rest/controller/UserController.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/services/ResourceServiceImpl.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/services/RoleServiceImpl.java
    syncope/trunk/core/src/main/java/org/apache/syncope/core/services/UserServiceImpl.java
    syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/RoleTestITCase.java
    syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java

Modified: syncope/trunk/common/src/main/java/org/apache/syncope/common/services/ResourceService.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/services/ResourceService.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/services/ResourceService.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/services/ResourceService.java Mon Oct  7 14:38:55 2013
@@ -30,6 +30,7 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.core.Response;
 import org.apache.syncope.common.to.BulkAction;
 import org.apache.syncope.common.to.BulkActionRes;
+import org.apache.syncope.common.to.BulkAssociationAction;
 import org.apache.syncope.common.to.ConnObjectTO;
 import org.apache.syncope.common.to.PropagationActionClassTO;
 import org.apache.syncope.common.to.ResourceTO;
@@ -110,4 +111,14 @@ public interface ResourceService {
     @POST
     @Path("bulk")
     BulkActionRes bulkAction(BulkAction bulkAction);
+
+    @PUT
+    @Path("{resourceName}/users")
+    BulkActionRes usersBulkAssociationAction(
+            @PathParam("resourceName") String resourceName, BulkAssociationAction bulkAction);
+
+    @PUT
+    @Path("{resourceName}/roles")
+    BulkActionRes rolesBulkAssociationAction(
+            @PathParam("resourceName") String resourceName, BulkAssociationAction bulkAction);
 }

Modified: syncope/trunk/common/src/main/java/org/apache/syncope/common/services/RoleService.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/services/RoleService.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/services/RoleService.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/services/RoleService.java Mon Oct  7 14:38:55 2013
@@ -30,6 +30,7 @@ import javax.ws.rs.core.Response;
 
 import org.apache.syncope.common.search.NodeCond;
 import org.apache.syncope.common.mod.RoleMod;
+import org.apache.syncope.common.to.PropagationTargetsTO;
 import org.apache.syncope.common.to.RoleTO;
 
 @Path("roles")
@@ -99,7 +100,7 @@ public interface RoleService {
     /**
      * @param searchCondition Filter condition for role list
      * @return Returns list of roles with matching filter conditions
-     * @throws InvalidSearchConditionException 
+     * @throws InvalidSearchConditionException
      */
     @POST
     @Path("search")
@@ -110,7 +111,7 @@ public interface RoleService {
      * @param page Page of roles in relation to size parameter
      * @param size Number of roles to be displayed per page
      * @return Returns paginated list of roles with matching filter conditions
-     * @throws InvalidSearchConditionException 
+     * @throws InvalidSearchConditionException
      */
     @POST
     @Path("search")
@@ -120,7 +121,7 @@ public interface RoleService {
     /**
      * @param searchCondition Filter condition for role list
      * @return Returns number of roles matching provided filter conditions
-     * @throws InvalidSearchConditionException 
+     * @throws InvalidSearchConditionException
      */
     @POST
     @Path("search/count")
@@ -146,4 +147,36 @@ public interface RoleService {
     @Path("{roleId}")
     RoleTO update(@PathParam("roleId") Long roleId, RoleMod roleMod);
 
+    /**
+     * Unlinks role and the given external resources specified by <tt>propagationTargetsTO</tt> parameter.
+     *
+     * @param roleId role id.
+     * @param propagationTargetsTO resource names.
+     * @return updated role.
+     */
+    @POST
+    @Path("{roleId}/unlink")
+    RoleTO unlink(@PathParam("roleId") Long roleId, PropagationTargetsTO propagationTargetsTO);
+
+    /**
+     * Unassigns resources to the given role (performs unlink + de-provision).
+     *
+     * @param roleId role id.
+     * @param propagationTargetsTO resources to be unassigned.
+     * @return updated role.
+     */
+    @POST
+    @Path("{roleId}/unassign")
+    RoleTO unassign(@PathParam("roleId") Long roleId, PropagationTargetsTO propagationTargetsTO);
+
+    /**
+     * De-provision role from the given resources without unlinking.
+     *
+     * @param roleId role id of the role to be de-provisioned.
+     * @param propagationTargetsTO resource names.
+     * @return updated role.
+     */
+    @POST
+    @Path("{roleId}/deprovision")
+    RoleTO deprovision(@PathParam("roleId") Long roleId, PropagationTargetsTO propagationTargetsTO);
 }
\ No newline at end of file

Modified: syncope/trunk/common/src/main/java/org/apache/syncope/common/services/UserService.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/services/UserService.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/services/UserService.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/services/UserService.java Mon Oct  7 14:38:55 2013
@@ -23,6 +23,7 @@ import javax.ws.rs.DELETE;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.QueryParam;
@@ -32,25 +33,26 @@ import org.apache.syncope.common.search.
 import org.apache.syncope.common.to.BulkAction;
 import org.apache.syncope.common.to.BulkActionRes;
 import org.apache.syncope.common.to.PropagationRequestTO;
+import org.apache.syncope.common.to.PropagationTargetsTO;
 import org.apache.syncope.common.to.UserTO;
 
 @Path("users")
 public interface UserService {
 
-    @POST
+    @PUT
     @Path("{userId}/status/activate")
     UserTO activate(@PathParam("userId") long userId, @QueryParam("token") String token);
 
-    @POST
+    @PUT
     @Path("{userId}/status/activate/propagation")
     UserTO activate(@PathParam("userId") long userId, @QueryParam("token") String token,
             PropagationRequestTO propagationRequestTO);
 
-    @POST
+    @PUT
     @Path("activateByUsername/{username}")
     UserTO activateByUsername(@PathParam("username") String username, @QueryParam("token") String token);
 
-    @POST
+    @PUT
     @Path("activateByUsername/{username}/propagation")
     UserTO activateByUsername(@PathParam("username") String username, @QueryParam("token") String token,
             PropagationRequestTO propagationRequestTO);
@@ -72,19 +74,19 @@ public interface UserService {
     @GET
     List<UserTO> list(@QueryParam("page") int page, @QueryParam("size") @DefaultValue("25") int size);
 
-    @POST
+    @PUT
     @Path("{userId}/status/reactivate")
     UserTO reactivate(@PathParam("userId") long userId);
 
-    @POST
+    @PUT
     @Path("{userId}/status/reactivate/propagation")
     UserTO reactivate(@PathParam("userId") long userId, PropagationRequestTO propagationRequestTO);
 
-    @POST
+    @PUT
     @Path("reactivateByUsername/{username}")
     UserTO reactivateByUsername(@PathParam("username") String username);
 
-    @POST
+    @PUT
     @Path("reactivateByUsername/{username}/propagation")
     UserTO reactivateByUsername(@PathParam("username") String username, PropagationRequestTO propagationRequestTO);
 
@@ -112,27 +114,60 @@ public interface UserService {
     @Path("search/count")
     int searchCount(NodeCond searchCondition) throws InvalidSearchConditionException;
 
-    @POST
+    @PUT
     @Path("{userId}/status/suspend")
     UserTO suspend(@PathParam("userId") long userId);
 
-    @POST
+    @PUT
     @Path("{userId}/status/suspend/propagation")
     UserTO suspend(@PathParam("userId") long userId, PropagationRequestTO propagationRequestTO);
 
-    @POST
+    @PUT
     @Path("suspendByUsername/{username}")
     UserTO suspendByUsername(@PathParam("username") String username);
 
-    @POST
+    @PUT
     @Path("suspendByUsername/{username}/propagation")
     UserTO suspendByUsername(@PathParam("username") String username, PropagationRequestTO propagationRequestTO);
 
-    @POST
+    @PUT
     @Path("{userId}")
     UserTO update(@PathParam("userId") Long userId, UserMod userMod);
 
     @POST
     @Path("bulk")
     BulkActionRes bulkAction(BulkAction bulkAction);
+
+    /**
+     * Unlinks user and the given external resources specified by <tt>propagationTargetsTO</tt> parameter.
+     *
+     * @param userId user id.
+     * @param propagationTargetsTO resource names.
+     * @return updated user.
+     */
+    @PUT
+    @Path("{userId}/unlink")
+    UserTO unlink(@PathParam("userId") Long userId, PropagationTargetsTO propagationTargetsTO);
+
+    /**
+     * Unassigns resources to the given user (performs unlink + de-provision).
+     *
+     * @param userId user id.
+     * @param propagationTargetsTO resources to be unassigned.
+     * @return updated user.
+     */
+    @PUT
+    @Path("{userId}/unassign")
+    UserTO unassign(@PathParam("userId") Long userId, PropagationTargetsTO propagationTargetsTO);
+
+    /**
+     * De-provision user from the given resources without unlinking.
+     *
+     * @param userId user id of the user to be de-provisioned.
+     * @param propagationTargetsTO resource names.
+     * @return updated user.
+     */
+    @PUT
+    @Path("{userId}/deprovision")
+    UserTO deprovision(@PathParam("userId") Long userId, PropagationTargetsTO propagationTargetsTO);
 }

Copied: syncope/trunk/common/src/main/java/org/apache/syncope/common/to/AttributableTargetsTO.java (from r1525003, syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java)
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/to/AttributableTargetsTO.java?p2=syncope/trunk/common/src/main/java/org/apache/syncope/common/to/AttributableTargetsTO.java&p1=syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java&r1=1525003&r2=1529856&rev=1529856&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/to/AttributableTargetsTO.java Mon Oct  7 14:38:55 2013
@@ -30,40 +30,27 @@ import org.apache.syncope.common.Abstrac
 /**
  * Propagation request on internal storage or on 0+ external resources.
  */
-@XmlRootElement(name = "propagationRequest")
+@XmlRootElement(name = "attributableTargets")
 @XmlType
-public class PropagationRequestTO extends AbstractBaseBean {
+public class AttributableTargetsTO extends AbstractBaseBean {
 
-    private static final long serialVersionUID = 7601716025754543004L;
+    private static final long serialVersionUID = -2410740018092105778L;
 
     /**
-     * External resources propagation is requested to.
+     * Attributables.
      */
-    private final Set<String> resources;
+    private final Set<Long> attributables;
 
-    /**
-     * Whether update should be performed on internal storage.
-     */
-    private boolean onSyncope;
-
-    public PropagationRequestTO() {
+    public AttributableTargetsTO() {
         super();
 
-        this.resources = new HashSet<String>();
-    }
-
-    public boolean isOnSyncope() {
-        return onSyncope;
-    }
-
-    public void setOnSyncope(final boolean onSyncope) {
-        this.onSyncope = onSyncope;
+        this.attributables = new HashSet<Long>();
     }
 
     @XmlElementWrapper(name = "resources")
     @XmlElement(name = "resource")
     @JsonProperty("resources")
-    public Set<String> getResources() {
-        return resources;
+    public Set<Long> getAttributables() {
+        return attributables;
     }
 }

Copied: syncope/trunk/common/src/main/java/org/apache/syncope/common/to/BulkAssociationAction.java (from r1525003, syncope/trunk/common/src/main/java/org/apache/syncope/common/to/BulkAction.java)
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/to/BulkAssociationAction.java?p2=syncope/trunk/common/src/main/java/org/apache/syncope/common/to/BulkAssociationAction.java&p1=syncope/trunk/common/src/main/java/org/apache/syncope/common/to/BulkAction.java&r1=1525003&r2=1529856&rev=1529856&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/to/BulkAction.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/to/BulkAssociationAction.java Mon Oct  7 14:38:55 2013
@@ -27,7 +27,7 @@ import org.apache.syncope.common.Abstrac
 
 @XmlRootElement(name = "bulkAction")
 @XmlType
-public class BulkAction extends AbstractBaseBean {
+public class BulkAssociationAction extends AbstractBaseBean {
 
     private static final long serialVersionUID = 1395353278878758961L;
 
@@ -35,11 +35,9 @@ public class BulkAction extends Abstract
     @XmlType(name = "bulkActionType")
     public enum Type {
 
-        DELETE,
-        REACTIVATE,
-        SUSPEND,
-        DRYRUN,
-        EXECUTE
+        UNLINK,
+        UNASSIGN,
+        DEPROVISION
 
     }
 
@@ -48,7 +46,7 @@ public class BulkAction extends Abstract
     /**
      * Serialized identifiers.
      */
-    private Collection<String> targets;
+    private Collection<Long> targets;
 
     public Type getOperation() {
         return operation;
@@ -58,17 +56,17 @@ public class BulkAction extends Abstract
         this.operation = operation;
     }
 
-    public void setTargets(final Collection<String> targets) {
+    public void setTargets(final Collection<Long> targets) {
         this.targets = targets;
     }
 
-    public Collection<String> getTargets() {
+    public Collection<Long> getTargets() {
         return targets;
     }
 
-    public void addTarget(final String target) {
+    public void addTarget(final Long target) {
         if (this.targets == null) {
-            this.targets = new ArrayList<String>();
+            this.targets = new ArrayList<Long>();
         }
 
         this.targets.add(target);

Modified: syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java Mon Oct  7 14:38:55 2013
@@ -18,38 +18,25 @@
  */
 package org.apache.syncope.common.to;
 
-import com.fasterxml.jackson.annotation.JsonProperty;
-import java.util.HashSet;
-import java.util.Set;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.XmlType;
-import org.apache.syncope.common.AbstractBaseBean;
 
 /**
  * Propagation request on internal storage or on 0+ external resources.
  */
 @XmlRootElement(name = "propagationRequest")
 @XmlType
-public class PropagationRequestTO extends AbstractBaseBean {
+public class PropagationRequestTO extends PropagationTargetsTO {
 
     private static final long serialVersionUID = 7601716025754543004L;
 
     /**
-     * External resources propagation is requested to.
-     */
-    private final Set<String> resources;
-
-    /**
      * Whether update should be performed on internal storage.
      */
     private boolean onSyncope;
 
     public PropagationRequestTO() {
         super();
-
-        this.resources = new HashSet<String>();
     }
 
     public boolean isOnSyncope() {
@@ -59,11 +46,4 @@ public class PropagationRequestTO extend
     public void setOnSyncope(final boolean onSyncope) {
         this.onSyncope = onSyncope;
     }
-
-    @XmlElementWrapper(name = "resources")
-    @XmlElement(name = "resource")
-    @JsonProperty("resources")
-    public Set<String> getResources() {
-        return resources;
-    }
 }

Copied: syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationTargetsTO.java (from r1525003, syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java)
URL: http://svn.apache.org/viewvc/syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationTargetsTO.java?p2=syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationTargetsTO.java&p1=syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java&r1=1525003&r2=1529856&rev=1529856&view=diff
==============================================================================
--- syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationRequestTO.java (original)
+++ syncope/trunk/common/src/main/java/org/apache/syncope/common/to/PropagationTargetsTO.java Mon Oct  7 14:38:55 2013
@@ -30,36 +30,23 @@ import org.apache.syncope.common.Abstrac
 /**
  * Propagation request on internal storage or on 0+ external resources.
  */
-@XmlRootElement(name = "propagationRequest")
+@XmlRootElement(name = "propagationTargets")
 @XmlType
-public class PropagationRequestTO extends AbstractBaseBean {
+public class PropagationTargetsTO extends AbstractBaseBean {
 
-    private static final long serialVersionUID = 7601716025754543004L;
+    private static final long serialVersionUID = -2410740018092105778L;
 
     /**
      * External resources propagation is requested to.
      */
     private final Set<String> resources;
 
-    /**
-     * Whether update should be performed on internal storage.
-     */
-    private boolean onSyncope;
-
-    public PropagationRequestTO() {
+    public PropagationTargetsTO() {
         super();
 
         this.resources = new HashSet<String>();
     }
 
-    public boolean isOnSyncope() {
-        return onSyncope;
-    }
-
-    public void setOnSyncope(final boolean onSyncope) {
-        this.onSyncope = onSyncope;
-    }
-
     @XmlElementWrapper(name = "resources")
     @XmlElement(name = "resource")
     @JsonProperty("resources")

Modified: syncope/trunk/console/pom.xml
URL: http://svn.apache.org/viewvc/syncope/trunk/console/pom.xml?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
    (empty)

Added: syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/ActionTableCheckGroup.java
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/ActionTableCheckGroup.java?rev=1529856&view=auto
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/ActionTableCheckGroup.java (added)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/ActionTableCheckGroup.java Mon Oct  7 14:38:55 2013
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2013 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.console.commons;
+
+import java.util.Collection;
+import org.apache.wicket.markup.html.form.CheckGroup;
+
+public class ActionTableCheckGroup<T> extends CheckGroup<T> {
+
+    private static final long serialVersionUID = 1288270558573401394L;
+
+    public ActionTableCheckGroup(String id,
+            Collection<T> collection) {
+        super(id, collection);
+    }
+
+    public boolean isCheckable(final T element) {
+        return true;
+    }
+}

Modified: syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/StatusBean.java
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/StatusBean.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/StatusBean.java (original)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/StatusBean.java Mon Oct  7 14:38:55 2013
@@ -21,17 +21,31 @@ package org.apache.syncope.console.commo
 import java.io.Serializable;
 import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.syncope.common.to.AbstractAttributableTO;
+import org.apache.syncope.common.to.RoleTO;
+import org.apache.syncope.common.to.UserTO;
 
 public class StatusBean implements Serializable {
 
     private static final long serialVersionUID = -5207260204921071129L;
 
-    private String resourceName = null;
+    private final Long attributableId;
+
+    private final String attributableName;
+
+    private final String resourceName;
 
     private String accountLink = null;
 
     private StatusUtils.Status status = StatusUtils.Status.OBJECT_NOT_FOUND;
 
+    public StatusBean(final AbstractAttributableTO attributable, String resourceName) {
+        this.attributableId = attributable.getId();
+        this.attributableName = attributable instanceof UserTO
+                ? ((UserTO) attributable).getUsername() : ((RoleTO) attributable).getName();
+        this.resourceName = resourceName;
+    }
+
     public String getAccountLink() {
         return accountLink;
     }
@@ -44,10 +58,6 @@ public class StatusBean implements Seria
         return resourceName;
     }
 
-    public void setResourceName(final String resourceName) {
-        this.resourceName = resourceName;
-    }
-
     public StatusUtils.Status getStatus() {
         return status;
     }
@@ -56,6 +66,14 @@ public class StatusBean implements Seria
         this.status = status;
     }
 
+    public Long getAttributableId() {
+        return attributableId;
+    }
+
+    public String getAttributableName() {
+        return attributableName;
+    }
+
     @Override
     public String toString() {
         return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);

Modified: syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/StatusUtils.java
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/StatusUtils.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/StatusUtils.java (original)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/commons/StatusUtils.java Mon Oct  7 14:38:55 2013
@@ -22,16 +22,27 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import org.apache.syncope.common.to.AbstractAttributableTO;
 import org.apache.syncope.common.to.AttributeTO;
 import org.apache.syncope.common.to.ConnObjectTO;
 import org.apache.syncope.common.to.PropagationRequestTO;
+import org.apache.syncope.common.to.PropagationTargetsTO;
+import org.apache.syncope.console.pages.panels.ImagePanel;
 import org.apache.syncope.console.pages.panels.StatusPanel;
 import org.apache.syncope.console.rest.AbstractAttributableRestClient;
+import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.model.AbstractReadOnlyModel;
+import org.apache.wicket.model.IModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,6 +50,8 @@ public class StatusUtils implements Seri
 
     private static final long serialVersionUID = 7238009174387184309L;
 
+    public static final String IMG_STATUES = "../statuses/";
+
     public enum Status {
 
         NOT_YET_SUBMITTED(""),
@@ -75,32 +88,57 @@ public class StatusUtils implements Seri
         this.restClient = restClient;
     }
 
-    public Map<String, ConnObjectTO> getConnectorObjects(final AbstractAttributableTO attributable) {
-        final Map<String, ConnObjectTO> objects = new HashMap<String, ConnObjectTO>();
+    public List<ConnObjectWrapper> getConnectorObjects(final Collection<AbstractAttributableTO> attributables) {
+        final List<ConnObjectWrapper> objects = new ArrayList<ConnObjectWrapper>();
+
+        for (AbstractAttributableTO attributableTO : attributables) {
+            objects.addAll(getConnectorObjects(attributableTO, attributableTO.getResources()));
+        }
+
+        return objects;
+    }
 
-        for (String resouceName : attributable.getResources()) {
+    public List<ConnObjectWrapper> getConnectorObjects(
+            final Collection<AbstractAttributableTO> attributables, final Collection<String> resources) {
+        final List<ConnObjectWrapper> objects = new ArrayList<ConnObjectWrapper>();
+
+        for (AbstractAttributableTO attributableTO : attributables) {
+            objects.addAll(getConnectorObjects(attributableTO, resources));
+        }
+
+        return objects;
+    }
+
+    private List<ConnObjectWrapper> getConnectorObjects(
+            final AbstractAttributableTO attributableTO, final Collection<String> resources) {
+        final List<ConnObjectWrapper> objects = new ArrayList<ConnObjectWrapper>();
+
+        for (String resourceName : resources) {
             ConnObjectTO objectTO = null;
             try {
-                objectTO = restClient.getConnectorObject(resouceName, attributable.getId());
+                objectTO = restClient.getConnectorObject(resourceName, attributableTO.getId());
             } catch (Exception e) {
-                LOG.warn("ConnObject '{}' not found on resource '{}'", attributable.getId(), resouceName);
+                LOG.warn("ConnObject '{}' not found on resource '{}'", attributableTO.getId(), resourceName);
             }
 
-            objects.put(resouceName, objectTO);
+            objects.add(new ConnObjectWrapper(attributableTO, resourceName, objectTO));
         }
 
         return objects;
     }
 
-    public StatusBean getStatusBean(final String resourceName, final ConnObjectTO objectTO) {
-        final StatusBean statusBean = new StatusBean();
-        statusBean.setResourceName(resourceName);
+    public StatusBean getStatusBean(
+            final AbstractAttributableTO attributable,
+            final String resourceName,
+            final ConnObjectTO objectTO,
+            final boolean isRole) {
+        final StatusBean statusBean = new StatusBean(attributable, resourceName);
 
         if (objectTO != null) {
             final Boolean enabled = isEnabled(objectTO);
 
             final StatusUtils.Status status = enabled == null
-                    ? StatusUtils.Status.UNDEFINED
+                    ? (isRole ? StatusUtils.Status.ACTIVE : StatusUtils.Status.UNDEFINED)
                     : enabled
                     ? StatusUtils.Status.ACTIVE
                     : StatusUtils.Status.SUSPENDED;
@@ -161,8 +199,23 @@ public class StatusUtils implements Seri
         return propagationRequestTO;
     }
 
-    public static void update(final StatusPanel statusPanel, final AjaxRequestTarget target,
-            final Collection<String> resourcesToAdd, final Collection<String> resourcesToRemove) {
+    public static PropagationTargetsTO buildPropagationTargetsTO(final Collection<StatusBean> statuses) {
+
+        final PropagationTargetsTO propagationTargetsTO = new PropagationTargetsTO();
+
+        for (StatusBean status : statuses) {
+            propagationTargetsTO.getResources().add(status.getResourceName());
+        }
+
+        return propagationTargetsTO;
+    }
+
+    public static void update(
+            final AbstractAttributableTO attributable,
+            final StatusPanel statusPanel,
+            final AjaxRequestTarget target,
+            final Collection<String> resourcesToAdd,
+            final Collection<String> resourcesToRemove) {
 
         if (statusPanel != null) {
             Map<String, StatusBean> statusMap = new LinkedHashMap<String, StatusBean>();
@@ -170,14 +223,13 @@ public class StatusUtils implements Seri
                 statusMap.put(statusBean.getResourceName(), statusBean);
             }
 
-            for (String resource : resourcesToAdd) {
-                if (!statusMap.keySet().contains(resource)) {
+            for (String resourceName : resourcesToAdd) {
+                if (!statusMap.keySet().contains(resourceName)) {
                     StatusBean statusBean;
-                    if (statusPanel.getInitialStatusBeanMap().containsKey(resource)) {
-                        statusBean = statusPanel.getInitialStatusBeanMap().get(resource);
+                    if (statusPanel.getInitialStatusBeanMap().containsKey(resourceName)) {
+                        statusBean = statusPanel.getInitialStatusBeanMap().get(resourceName);
                     } else {
-                        statusBean = new StatusBean();
-                        statusBean.setResourceName(resource);
+                        statusBean = new StatusBean(attributable, resourceName);
                         statusBean.setStatus(StatusUtils.Status.NOT_YET_SUBMITTED);
                     }
 
@@ -193,4 +245,187 @@ public class StatusUtils implements Seri
             target.add(statusPanel);
         }
     }
+
+    public ConnObjectTO getConnObjectTO(
+            final Long attributableId, final String resourceName, final List<ConnObjectWrapper> objects) {
+
+        for (ConnObjectWrapper object : objects) {
+            if (attributableId.equals(object.getAttributable())
+                    && resourceName.equalsIgnoreCase(object.getResourceName())) {
+                return object.getConnObjectTO();
+            }
+        }
+
+        return null;
+    }
+
+    public Image getStatusImage(final String componentId, final Status status) {
+        final String alt, title, statusName;
+
+        switch (status) {
+
+            case NOT_YET_SUBMITTED:
+                statusName = StatusUtils.Status.UNDEFINED.toString();
+                alt = "undefined icon";
+                title = "Not yet submitted";
+                break;
+
+            case ACTIVE:
+                statusName = StatusUtils.Status.ACTIVE.toString();
+                alt = "active icon";
+                title = "Enabled";
+                break;
+
+            case UNDEFINED:
+                statusName = StatusUtils.Status.UNDEFINED.toString();
+                alt = "undefined icon";
+                title = "Undefined status";
+                break;
+
+            case OBJECT_NOT_FOUND:
+                statusName = StatusUtils.Status.OBJECT_NOT_FOUND.toString();
+                alt = "notfound icon";
+                title = "Not found";
+                break;
+
+            default:
+                statusName = StatusUtils.Status.SUSPENDED.toString();
+                alt = "inactive icon";
+                title = "Disabled";
+        }
+
+        final Image img = new Image(componentId, IMG_STATUES + statusName + Constants.PNG_EXT);
+
+        img.add(new Behavior() {
+
+            private static final long serialVersionUID = 1469628524240283489L;
+
+            @Override
+            public void onComponentTag(final Component component, final ComponentTag tag) {
+                tag.put("alt", alt);
+                tag.put("title", title);
+            }
+        });
+
+        return img;
+    }
+
+    public ImagePanel getStatusImagePanel(final String componentId, final Status status) {
+        final String alt, title, statusName;
+
+        switch (status) {
+
+            case NOT_YET_SUBMITTED:
+                statusName = StatusUtils.Status.UNDEFINED.toString();
+                alt = "undefined icon";
+                title = "Not yet submitted";
+                break;
+
+            case ACTIVE:
+                statusName = StatusUtils.Status.ACTIVE.toString();
+                alt = "active icon";
+                title = "Enabled";
+                break;
+
+            case UNDEFINED:
+                statusName = StatusUtils.Status.UNDEFINED.toString();
+                alt = "undefined icon";
+                title = "Undefined status";
+                break;
+
+            case OBJECT_NOT_FOUND:
+                statusName = StatusUtils.Status.OBJECT_NOT_FOUND.toString();
+                alt = "notfound icon";
+                title = "Not found";
+                break;
+
+            default:
+                statusName = StatusUtils.Status.SUSPENDED.toString();
+                alt = "inactive icon";
+                title = "Disabled";
+        }
+
+        final ImagePanel imagePanel = new ImagePanel(componentId, IMG_STATUES + statusName + Constants.PNG_EXT);
+        imagePanel.add(new Behavior() {
+
+            private static final long serialVersionUID = 1469628524240283489L;
+
+            @Override
+            public void onComponentTag(final Component component, final ComponentTag tag) {
+                tag.put("alt", alt);
+                tag.put("title", title);
+            }
+        });
+
+        return imagePanel;
+    }
+
+    public static class ConnObjectWrapper {
+
+        private final AbstractAttributableTO attributable;
+
+        private final String resourceName;
+
+        private final ConnObjectTO connObjectTO;
+
+        public ConnObjectWrapper(AbstractAttributableTO attributable, String resourceName, ConnObjectTO connObjectTO) {
+            this.attributable = attributable;
+            this.resourceName = resourceName;
+            this.connObjectTO = connObjectTO;
+        }
+
+        public AbstractAttributableTO getAttributable() {
+            return attributable;
+        }
+
+        public String getResourceName() {
+            return resourceName;
+        }
+
+        public ConnObjectTO getConnObjectTO() {
+            return connObjectTO;
+        }
+    }
+
+    public static abstract class StatusBeanProvider extends SortableDataProvider<StatusBean, String> {
+
+        private static final long serialVersionUID = 4287357360778016173L;
+
+        private SortableDataProviderComparator<StatusBean> comparator;
+
+        public StatusBeanProvider(final String sort) {
+            //Default sorting
+            setSort(sort, SortOrder.ASCENDING);
+            comparator = new SortableDataProviderComparator<StatusBean>(this);
+        }
+
+        @Override
+        public Iterator<StatusBean> iterator(final long first, final long count) {
+            List<StatusBean> list = getStatusBeans();
+
+            Collections.sort(list, comparator);
+
+            return list.subList((int) first, (int) first + (int) count).iterator();
+        }
+
+        @Override
+        public long size() {
+            return getStatusBeans().size();
+        }
+
+        @Override
+        public IModel<StatusBean> model(final StatusBean resource) {
+            return new AbstractReadOnlyModel<StatusBean>() {
+
+                private static final long serialVersionUID = -7802635613997243712L;
+
+                @Override
+                public StatusBean getObject() {
+                    return resource;
+                }
+            };
+        }
+
+        public abstract List<StatusBean> getStatusBeans();
+    }
 }

Modified: syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/AbstractBasePage.java
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/AbstractBasePage.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/AbstractBasePage.java (original)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/AbstractBasePage.java Mon Oct  7 14:38:55 2013
@@ -22,6 +22,7 @@ import org.apache.syncope.console.common
 import org.apache.syncope.console.commons.XMLRolesReader;
 import org.apache.syncope.console.rest.ReportRestClient;
 import org.apache.syncope.console.rest.ResourceRestClient;
+import org.apache.syncope.console.rest.RoleRestClient;
 import org.apache.syncope.console.rest.SchemaRestClient;
 import org.apache.syncope.console.rest.TaskRestClient;
 import org.apache.syncope.console.rest.UserRestClient;
@@ -64,14 +65,17 @@ public class AbstractBasePage extends We
     protected UserRestClient userRestClient;
 
     @SpringBean
+    protected RoleRestClient roleRestClient;
+
+    @SpringBean
     protected TaskRestClient taskRestClient;
-    
+
     @SpringBean
     protected SchemaRestClient schemaRestClient;
-    
+
     @SpringBean
     protected ResourceRestClient resourceRestClient;
-    
+
     @SpringBean
     protected ReportRestClient reportRestClient;
 

Added: syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/AbstractStatusModlaPage.java
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/AbstractStatusModlaPage.java?rev=1529856&view=auto
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/AbstractStatusModlaPage.java (added)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/AbstractStatusModlaPage.java Mon Oct  7 14:38:55 2013
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2013 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.console.pages;
+
+public class AbstractStatusModlaPage extends BaseModalPage {
+
+    protected static final long serialVersionUID = 6633408683036028540L;
+
+}

Copied: syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ProvisioningModalPage.java (from r1525003, syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/StatusModalPage.java)
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ProvisioningModalPage.java?p2=syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ProvisioningModalPage.java&p1=syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/StatusModalPage.java&r1=1525003&r2=1529856&rev=1529856&view=diff
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/StatusModalPage.java (original)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ProvisioningModalPage.java Mon Oct  7 14:38:55 2013
@@ -19,125 +19,229 @@
 package org.apache.syncope.console.pages;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
 import java.util.List;
+import org.apache.syncope.common.search.NodeCond;
+import org.apache.syncope.common.search.ResourceCond;
+import org.apache.syncope.common.services.InvalidSearchConditionException;
 import org.apache.syncope.common.to.AbstractAttributableTO;
+import org.apache.syncope.common.to.BulkActionRes;
+import org.apache.syncope.common.to.BulkAssociationAction;
+import org.apache.syncope.common.to.ResourceTO;
+import org.apache.syncope.common.to.RoleTO;
 import org.apache.syncope.common.to.UserTO;
 import org.apache.syncope.console.commons.Constants;
 import org.apache.syncope.console.commons.StatusBean;
-import org.apache.syncope.console.pages.panels.StatusPanel;
+import org.apache.syncope.console.commons.StatusUtils;
+import org.apache.syncope.console.commons.StatusUtils.ConnObjectWrapper;
+import org.apache.syncope.console.pages.panels.ActionDataTablePanel;
+import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.markup.html.form.AjaxButton;
-import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
-import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
 import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.model.ResourceModel;
+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.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.StringResourceModel;
 
-public class StatusModalPage extends BaseModalPage {
+public class ProvisioningModalPage<T extends AbstractAttributableTO> extends AbstractStatusModlaPage {
 
     private static final long serialVersionUID = 4114026480146090961L;
 
-    public StatusModalPage(final PageReference pageRef, final ModalWindow window,
-            final AbstractAttributableTO attributable) {
+    private final ResourceTO resourceTO;
+
+    private final Class<? extends AbstractAttributableTO> typeRef;
+
+    private final PageReference pageRef;
+
+    private final ModalWindow window;
+
+    private int rowsPerPage = 25;
+
+    private final StatusUtils statusUtils;
+
+    public ProvisioningModalPage(
+            final PageReference pageRef,
+            final ModalWindow window,
+            final ResourceTO resourceTO,
+            final Class<T> typeRef) {
 
         super();
 
-        final Form form = new Form(FORM);
-        add(form);
+        this.pageRef = pageRef;
+        this.window = window;
+        this.resourceTO = resourceTO;
+        this.typeRef = typeRef;
+
+        statusUtils = new StatusUtils((UserTO.class.isAssignableFrom(typeRef) ? userRestClient : roleRestClient));
+
+        final List<IColumn<StatusBean, String>> columns = new ArrayList<IColumn<StatusBean, String>>();
+        columns.add(new PropertyColumn<StatusBean, String>(
+                new StringResourceModel("id", this, null, "Attributable id"), "attributableId", "attributableId"));
+        columns.add(new PropertyColumn<StatusBean, String>(
+                new StringResourceModel("name", this, null, "Attributable name"), "attributableName", "attributableName"));
+        columns.add(new PropertyColumn<StatusBean, String>(
+                new StringResourceModel("resourceName", this, null, "Resource name"), "resourceName", "resourceName"));
+        columns.add(new PropertyColumn<StatusBean, String>(
+                new StringResourceModel("accountLink", this, null, "Account link"), "accountLink", "accountLink"));
+        columns.add(new AbstractColumn<StatusBean, String>(
+                new StringResourceModel("status", this, null, "")) {
 
-        final List<StatusBean> statuses = new ArrayList<StatusBean>();
+            private static final long serialVersionUID = -3503023501954863131L;
 
-        final StatusPanel statusPanel = new StatusPanel("statuspanel", attributable, statuses, null);
-        MetaDataRoleAuthorizationStrategy.authorize(
-                statusPanel, RENDER, xmlRolesReader.getAllAllowedRoles("Resources", "getConnectorObject"));
-        form.add(statusPanel);
-
-        final AjaxButton disable;
-        if (attributable instanceof UserTO) {
-            disable = new IndicatingAjaxButton("disable", new ResourceModel("disable", "Disable")) {
-
-                private static final long serialVersionUID = -958724007591692537L;
-
-                @Override
-                protected void onSubmit(final AjaxRequestTarget target, final Form form) {
-                    try {
-                        userRestClient.suspend(attributable.getId(), statuses);
-
-                        if (pageRef.getPage() instanceof BasePage) {
-                            ((BasePage) pageRef.getPage()).setModalResult(true);
-                        }
-
-                        window.close(target);
-                    } catch (Exception e) {
-                        LOG.error("Error disabling resources", e);
-                        error(getString(Constants.ERROR) + ":" + e.getMessage());
-                        target.add(feedbackPanel);
-                    }
-                }
+            @Override
+            public String getCssClass() {
+                return "action";
+            }
+
+            @Override
+            public void populateItem(
+                    final Item<ICellPopulator<StatusBean>> cellItem,
+                    final String componentId,
+                    final IModel<StatusBean> model) {
+                cellItem.add(statusUtils.getStatusImagePanel(componentId, model.getObject().getStatus()));
+            }
+        });
 
-                @Override
-                protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+        final ActionDataTablePanel<StatusBean, String> table = new ActionDataTablePanel<StatusBean, String>(
+                "resourceDatatable",
+                columns,
+                (ISortableDataProvider<StatusBean, String>) new StatusBeanProvider(),
+                rowsPerPage,
+                pageRef);
+
+        final String pageId = "Resources";
+
+        table.addAction(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                try {
+                    bulkAssociationAction(target, BulkAssociationAction.Type.UNLINK, table, columns);
+                } catch (Exception e) {
+                    LOG.error("Error unlinkink resources", e);
+                    error(getString(Constants.ERROR) + ":" + e.getMessage());
                     target.add(feedbackPanel);
                 }
-            };
-        } else {
-            disable = new AjaxButton("disable") {
+            }
+        }, ActionLink.ActionType.UNLINK, pageId);
 
-                private static final long serialVersionUID = 5538299138211283825L;
+        table.addAction(new ActionLink() {
 
-            };
-            disable.setVisible(false);
-        }
-        form.add(disable);
+            private static final long serialVersionUID = -3722207913631435501L;
 
-        final AjaxButton enable;
-        if (attributable instanceof UserTO) {
-            enable = new IndicatingAjaxButton("enable", new ResourceModel("enable", "Enable")) {
-
-                private static final long serialVersionUID = -958724007591692537L;
-
-                @Override
-                protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
-                    try {
-                        userRestClient.reactivate(attributable.getId(), statuses);
-
-                        ((BasePage) pageRef.getPage()).setModalResult(true);
-
-                        window.close(target);
-                    } catch (Exception e) {
-                        LOG.error("Error enabling resources", e);
-                        error(getString(Constants.ERROR) + ":" + e.getMessage());
-                        target.add(feedbackPanel);
-                    }
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                try {
+                    bulkAssociationAction(target, BulkAssociationAction.Type.DEPROVISION, table, columns);
+                } catch (Exception e) {
+                    LOG.error("Error de-provisioning user", e);
+                    error(getString(Constants.ERROR) + ":" + e.getMessage());
+                    target.add(feedbackPanel);
                 }
+            }
+        }, ActionLink.ActionType.DEPROVISION, pageId);
 
-                @Override
-                protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+        table.addAction(new ActionLink() {
 
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                try {
+                    bulkAssociationAction(target, BulkAssociationAction.Type.UNASSIGN, table, columns);
+                } catch (Exception e) {
+                    LOG.error("Error unassigning resources", e);
+                    error(getString(Constants.ERROR) + ":" + e.getMessage());
                     target.add(feedbackPanel);
                 }
-            };
-        } else {
-            enable = new AjaxButton("enable") {
+            }
+        }, ActionLink.ActionType.UNASSIGN, pageId);
+
+        table.addCancelButton(window);
 
-                private static final long serialVersionUID = 5538299138211283825L;
+        add(table);
+    }
 
-            };
-            enable.setVisible(false);
+    private class StatusBeanProvider extends StatusUtils.StatusBeanProvider {
+
+        private static final long serialVersionUID = 4287357360778016173L;
+
+        public StatusBeanProvider() {
+            super("accountLink");
         }
-        form.add(enable);
 
-        final AjaxButton cancel = new IndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL)) {
+        @SuppressWarnings("unchecked")
+        @Override
+        public List<StatusBean> getStatusBeans() {
+            final ResourceCond res = new ResourceCond();
+            res.setResourceName(resourceTO.getName());
+
+            final List<T> attributables = new ArrayList<T>();
+
+            try {
+                if (UserTO.class.isAssignableFrom(typeRef)) {
+                    attributables.addAll((List<T>) userRestClient.search(NodeCond.getLeafCond(res), 0, rowsPerPage));
+                } else {
+                    attributables.addAll((List<T>) roleRestClient.search(NodeCond.getLeafCond(res), 0, rowsPerPage));
+                }
+            } catch (InvalidSearchConditionException e) {
+                LOG.warn("Invalid serach condition {}", res, e);
+            }
 
-            private static final long serialVersionUID = -958724007591692537L;
+            final List<ConnObjectWrapper> connObjects = statusUtils.getConnectorObjects(
+                    (List<AbstractAttributableTO>) attributables, Collections.<String>singleton(resourceTO.getName()));
 
-            @Override
-            protected void onSubmit(final AjaxRequestTarget target, final Form form) {
-                window.close(target);
+            final List<StatusBean> statusBeans = new ArrayList<StatusBean>(connObjects.size() + 1);
+            final LinkedHashMap<String, StatusBean> initialStatusBeanMap =
+                    new LinkedHashMap<String, StatusBean>(connObjects.size());
+
+            for (ConnObjectWrapper entry : connObjects) {
+                final StatusBean statusBean = statusUtils.getStatusBean(
+                        entry.getAttributable(),
+                        entry.getResourceName(),
+                        entry.getConnObjectTO(),
+                        RoleTO.class.isAssignableFrom(typeRef));
+
+                initialStatusBeanMap.put(entry.getResourceName(), statusBean);
+                statusBeans.add(statusBean);
             }
-        };
-        cancel.setDefaultFormProcessing(false);
-        form.add(cancel);
+
+            return statusBeans;
+        }
+    }
+
+    private void bulkAssociationAction(
+            final AjaxRequestTarget target,
+            final BulkAssociationAction.Type type,
+            final ActionDataTablePanel<StatusBean, String> table,
+            final List<IColumn<StatusBean, String>> columns) {
+        final BulkAssociationAction bulkAction = new BulkAssociationAction();
+        bulkAction.setOperation(type);
+
+        final List<StatusBean> beans = new ArrayList<StatusBean>(table.getModelObject());
+        for (StatusBean bean : beans) {
+            LOG.debug("Selected bean {}", bean);
+            bulkAction.addTarget(bean.getAttributableId());
+        }
+
+        if (!beans.isEmpty()) {
+            final BulkActionRes res =
+                    resourceRestClient.bulkAssociationAction(resourceTO.getName(), bulkAction, typeRef);
+
+            ((BasePage) pageRef.getPage()).setModalResult(true);
+
+            setResponsePage(new BulkActionResultModalPage<StatusBean, String>(
+                    window, beans, columns, res, "attributableId"));
+        } else {
+            window.close(target);
+        }
     }
 }

Modified: syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ResourceModalPage.java
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ResourceModalPage.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ResourceModalPage.java (original)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ResourceModalPage.java Mon Oct  7 14:38:55 2013
@@ -68,7 +68,7 @@ public class ResourceModalPage extends B
         //--------------------------------
         form.add(new ResourceDetailsPanel("details", resourceTO,
                 resourceRestClient.getPropagationActionsClasses(), createFlag));
-        
+
         form.add(new SysInfoPanel("systeminformation", resourceTO));
         //--------------------------------
 

Modified: syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/Resources.java
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/Resources.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/Resources.java (original)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/Resources.java Mon Oct  7 14:38:55 2013
@@ -25,6 +25,8 @@ import java.util.Iterator;
 import java.util.List;
 import org.apache.syncope.common.to.ConnInstanceTO;
 import org.apache.syncope.common.to.ResourceTO;
+import org.apache.syncope.common.to.RoleTO;
+import org.apache.syncope.common.to.UserTO;
 import org.apache.syncope.common.validation.SyncopeClientCompositeException;
 import org.apache.syncope.console.commons.Constants;
 import org.apache.syncope.console.commons.PreferenceManager;
@@ -98,6 +100,21 @@ public class Resources extends BasePage 
 
     private int connectorPaginatorRows;
 
+    /**
+     * Modal window to be used for user status management.
+     */
+    protected final ModalWindow statusmodal = new ModalWindow("statusModal");
+
+    /**
+     * Schemas to be shown modal window height.
+     */
+    private final static int STATUS_MODAL_WIN_HEIGHT = 500;
+
+    /**
+     * Schemas to be shown modal window width.
+     */
+    private final static int STATUS_MODAL_WIN_WIDTH = 700;
+
     public Resources(final PageParameters parameters) {
         super(parameters);
 
@@ -106,6 +123,12 @@ public class Resources extends BasePage 
         add(createConnectorWin = new ModalWindow("createConnectorWin"));
         add(editConnectorWin = new ModalWindow("editConnectorWin"));
 
+        statusmodal.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        statusmodal.setInitialHeight(STATUS_MODAL_WIN_HEIGHT);
+        statusmodal.setInitialWidth(STATUS_MODAL_WIN_WIDTH);
+        statusmodal.setCookieName("status-modal");
+        add(statusmodal);
+
         AjaxLink<Void> reloadLink = new ClearIndicatingAjaxLink<Void>("reloadLink", getPageReference()) {
 
             private static final long serialVersionUID = 3109256773218160485L;
@@ -153,7 +176,8 @@ public class Resources extends BasePage 
     private void setupResources() {
         List<IColumn<ResourceTO, String>> columns = new ArrayList<IColumn<ResourceTO, String>>();
 
-        columns.add(new PropertyColumn(new StringResourceModel("name", this, null), "name", "name"));
+        columns.add(
+                new PropertyColumn<ResourceTO, String>(new StringResourceModel("name", this, null), "name", "name"));
 
         columns.add(new AbstractColumn<ResourceTO, String>(
                 new StringResourceModel("connector", this, null, "connector")) {
@@ -197,9 +221,9 @@ public class Resources extends BasePage 
             }
         });
 
-        columns.add(new PropertyColumn(new StringResourceModel(
+        columns.add(new PropertyColumn<ResourceTO, String>(new StringResourceModel(
                 "propagationPrimary", this, null), "propagationPrimary", "propagationPrimary"));
-        columns.add(new PropertyColumn(new StringResourceModel(
+        columns.add(new PropertyColumn<ResourceTO, String>(new StringResourceModel(
                 "propagationPriority", this, null), "propagationPriority", "propagationPriority"));
 
         columns.add(new AbstractColumn<ResourceTO, String>(new StringResourceModel("actions", this, null, "")) {
@@ -225,6 +249,51 @@ public class Resources extends BasePage 
                     @Override
                     public void onClick(final AjaxRequestTarget target) {
 
+                        statusmodal.setPageCreator(new ModalWindow.PageCreator() {
+
+                            private static final long serialVersionUID = -7834632442532690940L;
+
+                            @Override
+                            public Page createPage() {
+                                return new ProvisioningModalPage<UserTO>(
+                                        getPageReference(), statusmodal, model.getObject(), UserTO.class);
+                            }
+                        });
+
+                        statusmodal.show(target);
+                    }
+                }, ActionLink.ActionType.MANAGE_USERS, "Resources");
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+
+                        statusmodal.setPageCreator(new ModalWindow.PageCreator() {
+
+                            private static final long serialVersionUID = -7834632442532690940L;
+
+                            @Override
+                            public Page createPage() {
+                                return new ProvisioningModalPage<RoleTO>(
+                                        getPageReference(), statusmodal, model.getObject(), RoleTO.class);
+                            }
+                        });
+
+                        statusmodal.show(target);
+                    }
+                }, ActionLink.ActionType.MANAGE_ROLES, "Resources");
+
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = -3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+
                         editResourceWin.setPageCreator(new ModalWindow.PageCreator() {
 
                             private static final long serialVersionUID = -7834632442532690940L;
@@ -349,15 +418,15 @@ public class Resources extends BasePage 
     private void setupConnectors() {
         List<IColumn<ConnInstanceTO, String>> columns = new ArrayList<IColumn<ConnInstanceTO, String>>();
 
-        columns.add(new PropertyColumn(
+        columns.add(new PropertyColumn<ConnInstanceTO, String>(
                 new StringResourceModel("id", this, null), "id", "id"));
-        columns.add(new PropertyColumn(
+        columns.add(new PropertyColumn<ConnInstanceTO, String>(
                 new StringResourceModel("name", this, null), "connectorName", "connectorName"));
-        columns.add(new PropertyColumn(
+        columns.add(new PropertyColumn<ConnInstanceTO, String>(
                 new StringResourceModel("displayName", this, null), "displayName", "displayName"));
-        columns.add(new PropertyColumn(
+        columns.add(new PropertyColumn<ConnInstanceTO, String>(
                 new StringResourceModel("bundleName", this, null), "bundleName", "bundleName"));
-        columns.add(new PropertyColumn(
+        columns.add(new PropertyColumn<ConnInstanceTO, String>(
                 new StringResourceModel("version", this, null), "version", "version"));
         columns.add(new AbstractColumn<ConnInstanceTO, String>(new StringResourceModel("actions", this, null, "")) {
 
@@ -486,8 +555,11 @@ public class Resources extends BasePage 
         MetaDataRoleAuthorizationStrategy.authorize(paginatorForm, RENDER, xmlRolesReader.getAllAllowedRoles(
                 "Connectors", "list"));
 
-        final DropDownChoice rowsChooser = new DropDownChoice("rowsChooser", new PropertyModel(this,
-                "connectorPaginatorRows"), prefMan.getPaginatorChoices());
+        final DropDownChoice<Integer> rowsChooser = new DropDownChoice<Integer>(
+                "rowsChooser",
+                new PropertyModel<Integer>(this,
+                "connectorPaginatorRows"),
+                prefMan.getPaginatorChoices());
 
         rowsChooser.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
 

Modified: syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ResultStatusModalPage.java
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ResultStatusModalPage.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ResultStatusModalPage.java (original)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/ResultStatusModalPage.java Mon Oct  7 14:38:55 2013
@@ -381,7 +381,8 @@ public class ResultStatusModalPage exten
     private Fragment getStatusIcon(final String id, final String resourceName, final ConnObjectTO objectTO) {
         final Image image;
         final String alt, title;
-        switch (statusUtils.getStatusBean(resourceName, objectTO).getStatus()) {
+        switch (statusUtils.getStatusBean(
+                attributable, resourceName, objectTO, this.attributable instanceof RoleTO).getStatus()) {
 
             case ACTIVE:
                 image = new Image("status", IMG_STATUSES + StatusUtils.Status.ACTIVE.toString()

Modified: syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/StatusModalPage.java
URL: http://svn.apache.org/viewvc/syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/StatusModalPage.java?rev=1529856&r1=1529855&r2=1529856&view=diff
==============================================================================
--- syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/StatusModalPage.java (original)
+++ syncope/trunk/console/src/main/java/org/apache/syncope/console/pages/StatusModalPage.java Mon Oct  7 14:38:55 2013
@@ -18,51 +18,138 @@
  */
 package org.apache.syncope.console.pages;
 
+import static org.apache.syncope.console.pages.AbstractBasePage.LOG;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import org.apache.syncope.common.to.AbstractAttributableTO;
+import org.apache.syncope.common.to.RoleTO;
 import org.apache.syncope.common.to.UserTO;
 import org.apache.syncope.console.commons.Constants;
 import org.apache.syncope.console.commons.StatusBean;
-import org.apache.syncope.console.pages.panels.StatusPanel;
+import org.apache.syncope.console.commons.StatusUtils;
+import org.apache.syncope.console.commons.StatusUtils.ConnObjectWrapper;
+import org.apache.syncope.console.commons.StatusUtils.Status;
+import org.apache.syncope.console.commons.StatusUtils.StatusBeanProvider;
+import org.apache.syncope.console.pages.panels.ActionDataTablePanel;
+import org.apache.syncope.console.wicket.markup.html.form.ActionLink;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.markup.html.form.AjaxButton;
-import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
-import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
 import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.model.ResourceModel;
+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.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.StringResourceModel;
 
-public class StatusModalPage extends BaseModalPage {
+public class StatusModalPage<T extends AbstractAttributableTO> extends AbstractStatusModlaPage {
 
     private static final long serialVersionUID = 4114026480146090961L;
 
-    public StatusModalPage(final PageReference pageRef, final ModalWindow window,
-            final AbstractAttributableTO attributable) {
+    private final AbstractAttributableTO attributableTO;
+
+    private int rowsPerPage = 25;
+
+    final StatusUtils statusUtils;
+
+    final boolean statusOnly;
+
+    public StatusModalPage(
+            final PageReference pageRef,
+            final ModalWindow window,
+            final AbstractAttributableTO attributableTO) {
+        this(pageRef, window, attributableTO, false);
+    }
+
+    public StatusModalPage(
+            final PageReference pageRef,
+            final ModalWindow window,
+            final AbstractAttributableTO attributableTO,
+            final boolean statusOnly) {
 
         super();
 
-        final Form form = new Form(FORM);
-        add(form);
+        this.statusOnly = statusOnly;
+        this.attributableTO = attributableTO;
+
+        statusUtils = new StatusUtils(attributableTO instanceof UserTO ? userRestClient : roleRestClient);
+
+        final List<IColumn<StatusBean, String>> columns = new ArrayList<IColumn<StatusBean, String>>();
+        columns.add(new PropertyColumn<StatusBean, String>(
+                new StringResourceModel("resourceName", this, null, "Resource name"), "resourceName", "resourceName"));
+        columns.add(new PropertyColumn<StatusBean, String>(
+                new StringResourceModel("accountLink", this, null, "Account link"), "accountLink", "accountLink"));
+        columns.add(new AbstractColumn<StatusBean, String>(
+                new StringResourceModel("status", this, null, "")) {
+
+            private static final long serialVersionUID = -3503023501954863131L;
+
+            @Override
+            public String getCssClass() {
+                return "action";
+            }
+
+            @Override
+            public void populateItem(
+                    final Item<ICellPopulator<StatusBean>> cellItem,
+                    final String componentId,
+                    final IModel<StatusBean> model) {
+
+                cellItem.add(statusUtils.getStatusImagePanel(componentId, model.getObject().getStatus()));
+            }
+        });
+
+        final ActionDataTablePanel<StatusBean, String> table = new ActionDataTablePanel<StatusBean, String>(
+                "resourceDatatable",
+                columns,
+                (ISortableDataProvider<StatusBean, String>) new AttributableStatusProvider(),
+                rowsPerPage,
+                pageRef) {
+
+            private static final long serialVersionUID = 6510391461033818316L;
+
+            @Override
+            public boolean isElementEnabled(final StatusBean element) {
+                return !statusOnly || element.getStatus() != Status.OBJECT_NOT_FOUND;
+            }
+        };
+
+        final String pageId = attributableTO instanceof RoleTO ? "Roles" : "Users";
 
-        final List<StatusBean> statuses = new ArrayList<StatusBean>();
+        if (statusOnly) {
+            table.addAction(new ActionLink() {
 
-        final StatusPanel statusPanel = new StatusPanel("statuspanel", attributable, statuses, null);
-        MetaDataRoleAuthorizationStrategy.authorize(
-                statusPanel, RENDER, xmlRolesReader.getAllAllowedRoles("Resources", "getConnectorObject"));
-        form.add(statusPanel);
+                private static final long serialVersionUID = -3722207913631435501L;
 
-        final AjaxButton disable;
-        if (attributable instanceof UserTO) {
-            disable = new IndicatingAjaxButton("disable", new ResourceModel("disable", "Disable")) {
+                @Override
+                public void onClick(final AjaxRequestTarget target) {
+                    try {
+                        userRestClient.reactivate(
+                                attributableTO.getId(), new ArrayList<StatusBean>(table.getModelObject()));
 
-                private static final long serialVersionUID = -958724007591692537L;
+                        ((BasePage) pageRef.getPage()).setModalResult(true);
+
+                        window.close(target);
+                    } catch (Exception e) {
+                        LOG.error("Error enabling resources", e);
+                        error(getString(Constants.ERROR) + ":" + e.getMessage());
+                        target.add(feedbackPanel);
+                    }
+                }
+            }, ActionLink.ActionType.REACTIVATE, pageId);
+
+            table.addAction(new ActionLink() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
 
                 @Override
-                protected void onSubmit(final AjaxRequestTarget target, final Form form) {
+                public void onClick(final AjaxRequestTarget target) {
                     try {
-                        userRestClient.suspend(attributable.getId(), statuses);
+                        userRestClient.suspend(
+                                attributableTO.getId(), new ArrayList<StatusBean>(table.getModelObject()));
 
                         if (pageRef.getPage() instanceof BasePage) {
                             ((BasePage) pageRef.getPage()).setModalResult(true);
@@ -75,69 +162,138 @@ public class StatusModalPage extends Bas
                         target.add(feedbackPanel);
                     }
                 }
+            }, ActionLink.ActionType.SUSPEND, pageId);
+        } else {
+            table.addAction(new ActionLink() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
 
                 @Override
-                protected void onError(final AjaxRequestTarget target, final Form<?> form) {
-                    target.add(feedbackPanel);
-                }
-            };
-        } else {
-            disable = new AjaxButton("disable") {
+                public void onClick(final AjaxRequestTarget target) {
+                    try {
+                        if (attributableTO instanceof UserTO) {
+                            userRestClient.unlink(
+                                    attributableTO.getId(), new ArrayList<StatusBean>(table.getModelObject()));
+                        } else {
+                            roleRestClient.unlink(
+                                    attributableTO.getId(), new ArrayList<StatusBean>(table.getModelObject()));
+                        }
 
-                private static final long serialVersionUID = 5538299138211283825L;
+                        ((BasePage) pageRef.getPage()).setModalResult(true);
 
-            };
-            disable.setVisible(false);
-        }
-        form.add(disable);
+                        window.close(target);
+                    } catch (Exception e) {
+                        LOG.error("Error unlinkink resources", e);
+                        error(getString(Constants.ERROR) + ":" + e.getMessage());
+                        target.add(feedbackPanel);
+                    }
+                }
+            }, ActionLink.ActionType.UNLINK, pageId);
 
-        final AjaxButton enable;
-        if (attributable instanceof UserTO) {
-            enable = new IndicatingAjaxButton("enable", new ResourceModel("enable", "Enable")) {
+            table.addAction(new ActionLink() {
 
-                private static final long serialVersionUID = -958724007591692537L;
+                private static final long serialVersionUID = -3722207913631435501L;
 
                 @Override
-                protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+                public void onClick(final AjaxRequestTarget target) {
                     try {
-                        userRestClient.reactivate(attributable.getId(), statuses);
+                        if (attributableTO instanceof UserTO) {
+                            userRestClient.deprovision(
+                                    attributableTO.getId(), new ArrayList<StatusBean>(table.getModelObject()));
+                        } else {
+                            roleRestClient.deprovision(
+                                    attributableTO.getId(), new ArrayList<StatusBean>(table.getModelObject()));
+                        }
 
                         ((BasePage) pageRef.getPage()).setModalResult(true);
 
                         window.close(target);
                     } catch (Exception e) {
-                        LOG.error("Error enabling resources", e);
+                        LOG.error("Error de-provisioning user", e);
                         error(getString(Constants.ERROR) + ":" + e.getMessage());
                         target.add(feedbackPanel);
                     }
                 }
+            }, ActionLink.ActionType.DEPROVISION, pageId);
+
+            table.addAction(new ActionLink() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
 
                 @Override
-                protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+                public void onClick(final AjaxRequestTarget target) {
+                    try {
+                        if (attributableTO instanceof UserTO) {
+                            userRestClient.unassign(
+                                    attributableTO.getId(), new ArrayList<StatusBean>(table.getModelObject()));
+                        } else {
+                            roleRestClient.unassign(
+                                    attributableTO.getId(), new ArrayList<StatusBean>(table.getModelObject()));
+                        }
+
+                        ((BasePage) pageRef.getPage()).setModalResult(true);
 
-                    target.add(feedbackPanel);
+                        window.close(target);
+                    } catch (Exception e) {
+                        LOG.error("Error unassigning resources", e);
+                        error(getString(Constants.ERROR) + ":" + e.getMessage());
+                        target.add(feedbackPanel);
+                    }
                 }
-            };
-        } else {
-            enable = new AjaxButton("enable") {
+            }, ActionLink.ActionType.UNASSIGN, pageId);
+        }
+
+        table.addCancelButton(window);
+
+        add(table);
+    }
 
-                private static final long serialVersionUID = 5538299138211283825L;
+    class AttributableStatusProvider extends StatusBeanProvider {
 
-            };
-            enable.setVisible(false);
+        private static final long serialVersionUID = 4586969457669796621L;
+
+        public AttributableStatusProvider() {
+            super("resourceName");
         }
-        form.add(enable);
 
-        final AjaxButton cancel = new IndicatingAjaxButton(CANCEL, new ResourceModel(CANCEL)) {
+        @SuppressWarnings("unchecked")
+        @Override
+        public List<StatusBean> getStatusBeans() {
 
-            private static final long serialVersionUID = -958724007591692537L;
+            final List<ConnObjectWrapper> connObjects =
+                    statusUtils.getConnectorObjects(Collections.<AbstractAttributableTO>singleton(attributableTO));
 
-            @Override
-            protected void onSubmit(final AjaxRequestTarget target, final Form form) {
-                window.close(target);
+            final List<StatusBean> statusBeans = new ArrayList<StatusBean>(connObjects.size() + 1);
+
+            if (statusOnly) {
+                final StatusBean syncope = new StatusBean(attributableTO, "Syncope");
+
+                syncope.setAccountLink(((UserTO) attributableTO).getUsername());
+
+                Status syncopeStatus = Status.UNDEFINED;
+                if (((UserTO) attributableTO).getStatus() != null) {
+                    try {
+                        syncopeStatus = Status.valueOf(((UserTO) attributableTO).getStatus().toUpperCase());
+                    } catch (IllegalArgumentException e) {
+                        LOG.warn("Unexpected status found: {}", ((UserTO) attributableTO).getStatus(), e);
+                    }
+                }
+                syncope.setStatus(syncopeStatus);
+
+                statusBeans.add(syncope);
             }
-        };
-        cancel.setDefaultFormProcessing(false);
-        form.add(cancel);
+
+            for (ConnObjectWrapper entry : connObjects) {
+                final StatusBean statusBean = statusUtils.getStatusBean(
+                        entry.getAttributable(),
+                        entry.getResourceName(),
+                        entry.getConnObjectTO(),
+                        attributableTO instanceof RoleTO);
+
+                statusBeans.add(statusBean);
+            }
+
+            return statusBeans;
+        }
     }
 }