Removed UserGroupJson & updated listUserGroups and createUserGroup
services.

Change-Id: I8ee08f6f672240844df31b6ef35bef4235ecf0c6
diff --git a/full/Changes b/full/Changes
index b8b6e88..8ebee1b 100644
--- a/full/Changes
+++ b/full/Changes
@@ -6,6 +6,10 @@
 11/11/2019
    - Updated user group service paths and replaced groupId with groupName 
      (margaretha, resolved #33)
+12/11/2019
+   - Removed UserGroupJson & updated listUserGroups and createUserGroup 
+     services (margaretha)
+     
 
 # version 0.62.1
 08/07/2019
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
index 78dcd55..14391d0 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
@@ -33,7 +33,6 @@
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.utils.ParameterChecker;
 import de.ids_mannheim.korap.web.controller.UserGroupController;
-import de.ids_mannheim.korap.web.input.UserGroupJson;
 
 /**
  * UserGroupService defines the logic behind user group web
@@ -207,29 +206,30 @@
      * 
      * @see /full/src/main/resources/db/predefined/V3.2__insert_predefined_roles.sql
      * 
-     * @param groupJson
-     *            UserGroupJson object from json
      * @param createdBy
      *            the user creating the group
      * @throws KustvaktException
      * 
      * 
      */
-    public void createUserGroup (UserGroupJson groupJson, String createdBy)
+    public boolean createUserGroup (String groupName, String members, String createdBy)
             throws KustvaktException {
-
-        String name = groupJson.getName();
-        if (!groupNamePattern.matcher(name).matches()) {
+        ParameterChecker.checkStringValue(groupName, "groupName");
+        ParameterChecker.checkStringValue(createdBy, "createdBy");
+        
+        if (!groupNamePattern.matcher(groupName).matches()) {
             throw new KustvaktException(StatusCodes.INVALID_ARGUMENT,
                     "User-group name must only contains letters, numbers, "
                             + "underscores, hypens and spaces",
-                    name);
+                    groupName);
         }
         
+        UserGroup userGroup = null;
+        boolean groupExists = false;
         try{
-            userGroupDao.retrieveGroupByName(groupJson.getName(),false);
-            throw new KustvaktException(StatusCodes.GROUP_EXISTS,
-                    "User-group name must be unique.");
+            userGroup = userGroupDao.retrieveGroupByName(groupName,false);
+            groupExists = true;
+            
         }
         catch (KustvaktException e) {
             if (e.getStatusCode() != StatusCodes.NO_RESOURCE_FOUND){
@@ -237,38 +237,40 @@
             }
         }
         
-        int groupId=0;
-        try {
-            groupId = userGroupDao.createGroup(name, createdBy,
-                    UserGroupStatus.ACTIVE);
-        }
-        // handle DB exceptions, e.g. unique constraint
-        catch (Exception e) {
-            Throwable cause = e;
-            Throwable lastCause = null;
-            while ((cause = cause.getCause()) != null
-                    && !cause.equals(lastCause)) {
-                if (cause instanceof SQLException) {
-                    break;
-                }
-                lastCause = cause;
+        if (!groupExists){
+            try {
+                userGroupDao.createGroup(groupName, createdBy,
+                        UserGroupStatus.ACTIVE);
+                userGroup = userGroupDao.retrieveGroupByName(groupName,false);
             }
-            throw new KustvaktException(StatusCodes.DB_INSERT_FAILED,
-                    cause.getMessage());
-        }
-        
-        UserGroup userGroup = userGroupDao.retrieveGroupById(groupId);
-
-        if (groupJson.getMembers() != null){
-            for (String memberId : groupJson.getMembers()) {
-                if (memberId.equals(createdBy)) {
-                    // skip owner, already added while creating group.
-                    continue;
+            // handle DB exceptions, e.g. unique constraint
+            catch (Exception e) {
+                Throwable cause = e;
+                Throwable lastCause = null;
+                while ((cause = cause.getCause()) != null
+                        && !cause.equals(lastCause)) {
+                    if (cause instanceof SQLException) {
+                        break;
+                    }
+                    lastCause = cause;
                 }
-                inviteGroupMember(memberId, userGroup, createdBy,
-                        GroupMemberStatus.PENDING);
+                throw new KustvaktException(StatusCodes.DB_INSERT_FAILED,
+                        cause.getMessage());
+            }
+            
+            if (members != null && !members.isEmpty()){
+                String[] groupMembers = members.split(",");
+                for (String memberUsername : groupMembers) {
+                    if (memberUsername.equals(createdBy)) {
+                        // skip owner, already added while creating group.
+                        continue;
+                    }
+                    inviteGroupMember(memberUsername, userGroup, createdBy,
+                            GroupMemberStatus.PENDING);
+                }
             }
         }
+        return groupExists;
     }
 
     public void deleteGroup (String groupName, String username)
@@ -391,11 +393,11 @@
         return null;
     }
 
-    public void inviteGroupMembers (UserGroupJson group, String groupName,
+    public void inviteGroupMembers (String groupName, String groupMembers,
             String inviter) throws KustvaktException {
-        String[] members = group.getMembers();
+        String[] members = groupMembers.split(",");
         ParameterChecker.checkStringValue(groupName, "group name");
-        ParameterChecker.checkObjectValue(members, "members");
+        ParameterChecker.checkStringValue(groupMembers, "members");
 
         UserGroup userGroup = retrieveUserGroupByName(groupName);
         if (userGroup.getStatus() == UserGroupStatus.DELETED) {
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
index 013b61a..3b5ed18 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserGroupController.java
@@ -7,6 +7,7 @@
 import javax.ws.rs.FormParam;
 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.Produces;
@@ -16,6 +17,7 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
 
+import org.apache.http.HttpStatus;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 
@@ -33,7 +35,6 @@
 import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
 import de.ids_mannheim.korap.web.filter.BlockingFilter;
 import de.ids_mannheim.korap.web.filter.PiwikFilter;
-import de.ids_mannheim.korap.web.input.UserGroupJson;
 
 /**
  * UserGroupController defines web APIs related to user groups,
@@ -64,7 +65,8 @@
      * Returns all user-groups in which a user is an active or a
      * pending member.
      * 
-     * Not suitable for system-admin, instead use {@link UserGroupController#
+     * Not suitable for system-admin, instead use
+     * {@link UserGroupController#
      * getUserGroupBySystemAdmin(SecurityContext, String, UserGroupStatus)}
      * 
      * @param securityContext
@@ -72,9 +74,8 @@
      * 
      */
     @GET
-    @Path("list")
     @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-    public List<UserGroupDto> getUserGroup (
+    public List<UserGroupDto> listUserGroups (
             @Context SecurityContext securityContext) {
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
@@ -88,13 +89,15 @@
     }
 
     /**
-     * Lists user-groups for system-admin purposes. If username
-     * parameter is not specified, list user-groups of all users. If
-     * status is not specified, list user-groups of all statuses.
+     * Lists user-groups for system-admin purposes. If username is
+     * specified, lists user-groups of the given user, otherwise list
+     * user-groups of all users. If status specified, list only
+     * user-groups with the given status, otherwise list user-groups
+     * regardless of their status.
      * 
      * @param securityContext
      * @param username
-     *            username
+     *            a username
      * @param status
      *            {@link UserGroupStatus}
      * @return a list of user-groups
@@ -146,37 +149,48 @@
     }
 
     /**
-     * Creates a user group where the user in token context is the
-     * group owner, and assigns the listed group members with status
+     * Creates a user group where the user in the token context is the
+     * group owner, and invites all users specified as members, see
+     * {@link #inviteGroupMembers(SecurityContext, String, UserGroupJson)}.
+     * The invited users are added as group members with status
      * GroupMemberStatus.PENDING.
      * 
-     * Invitations must be sent to these proposed members. If a member
-     * accepts the invitation, update his GroupMemberStatus to
-     * GroupMemberStatus.ACTIVE by using
-     * {@link UserGroupController#subscribeToGroup(SecurityContext, String)}.
+     * If a user accepts the invitation by using the service:
+     * {@link UserGroupController#subscribeToGroup(SecurityContext, String)},
+     * his GroupMemberStatus will be updated to
+     * GroupMemberStatus.ACTIVE.
      * 
-     * If he rejects the invitation, update his GroupMemberStatus
-     * to GroupMemberStatus.DELETED using
-     * {@link UserGroupController#unsubscribeFromGroup(SecurityContext, String)}.
-     * 
-     * 
+     * If a user rejects the invitation by using the service:
+     * {@link UserGroupController#unsubscribeFromGroup(SecurityContext, String)},
+     * his GroupMemberStatus will be updated to
+     * GroupMemberStatus.DELETED.
      * 
      * @param securityContext
-     * @param group
-     *            UserGroupJson
-     * @return if successful, HTTP response status OK
+     * @param members
+     *            usernames of users to be invited as group members
+     *            (separated by comma)
+     * @return if a new group created, HTTP response status 201
+     *         Created, otherwise 204 No Content.
      */
-    @POST
-    @Path("create")
-    @Consumes(MediaType.APPLICATION_JSON)
+    @PUT
+    @Path("{groupName}")
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     public Response createUserGroup (@Context SecurityContext securityContext,
-            UserGroupJson group) {
+            @PathParam("groupName") String groupName,
+            @FormParam("members") String members) {
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
         try {
             scopeService.verifyScope(context, OAuth2Scope.CREATE_USER_GROUP);
-            service.createUserGroup(group, context.getUsername());
-            return Response.ok("SUCCESS").build();
+            boolean groupExists = service.createUserGroup(groupName, members,
+                    context.getUsername());
+            if (groupExists) {
+                return Response.noContent().build();
+            }
+            else {
+                return Response.status(HttpStatus.SC_CREATED).build();
+            }
+
         }
         catch (KustvaktException e) {
             throw kustvaktResponseHandler.throwit(e);
@@ -184,11 +198,12 @@
     }
 
     /**
-     * Deletes a user-group specified by the group id. Only group
+     * Deletes a user-group specified by the group name. Only group
      * owner and system admins can delete groups.
      * 
      * @param securityContext
-     * @param groupName the name of the group to delete
+     * @param groupName
+     *            the name of the group to delete
      * @return HTTP 200, if successful.
      */
     @DELETE
@@ -207,11 +222,10 @@
         }
     }
 
-
     /**
-     * Removes a user-group member. Group owner cannot be deleted.
+     * Removes a user-group member. Group owner cannot be removed.
      * Only group admins, system admins and the member himself can
-     * remove a member. 
+     * remove a member.
      * 
      * @param securityContext
      * @param memberUsername
@@ -241,29 +255,28 @@
     }
 
     /**
-     * Invites group members to join a user-group specified in the
-     * JSON object.
-     * Only user-group admins and system admins are allowed.
+     * Invites users to join a user-group specified by the
+     * groupName.Only user-group admins and system admins are allowed.
      * 
      * @param securityContext
-     * @param group
-     *            UserGroupJson containing groupName and usernames to be
-     *            invited as members
+     * @param members
+     *            usernames separated by comma
      * @return if successful, HTTP response status OK
      */
     @POST
     @Path("{groupName}/invite")
-    @Consumes(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     public Response inviteGroupMembers (
             @Context SecurityContext securityContext,
             @PathParam("groupName") String groupName,
-            UserGroupJson group) {
+            @FormParam("members") String members) {
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
         try {
             scopeService.verifyScope(context,
                     OAuth2Scope.ADD_USER_GROUP_MEMBER);
-            service.inviteGroupMembers(group, groupName, context.getUsername());
+            service.inviteGroupMembers(groupName, members,
+                    context.getUsername());
             return Response.ok("SUCCESS").build();
         }
         catch (KustvaktException e) {
@@ -276,9 +289,9 @@
      * as well.
      * 
      * @param securityContext
-     * @param groupName
-     * @param memberUsername
-     * @param roleIds
+     * @param groupName the group name
+     * @param memberUsername the username of a group-member 
+     * @param roleIds the role ids for the member
      * @return
      */
     @POST
@@ -338,7 +351,8 @@
 
     /**
      * Updates the roles of a member of a user-group by removing the
-     * given roles. Only user-group admins and system admins are allowed.
+     * given roles. Only user-group admins and system admins are
+     * allowed.
      * 
      * @param securityContext
      * @param groupName
@@ -400,7 +414,8 @@
      * Handles requests to reject membership invitation. A member can
      * only unsubscribe him/herself from a group.
      * 
-     * Implemented identical to {@link #removeUserFromGroup(SecurityContext, String, String)}.
+     * Implemented identical to
+     * {@link #removeUserFromGroup(SecurityContext, String, String)}.
      * 
      * @param securityContext
      * @param groupName
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/input/UserGroupJson.java b/full/src/main/java/de/ids_mannheim/korap/web/input/UserGroupJson.java
index f89743e..6868262 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/input/UserGroupJson.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/input/UserGroupJson.java
@@ -10,11 +10,11 @@
  * @author margaretha
  * @see UserGroupController
  */
+@Deprecated
 @Getter
 @Setter
 public class UserGroupJson {
 
-    @Deprecated
     private int id;
     private String name;
     private String[] members;
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
index b6a2a2c..455d311 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
@@ -49,7 +49,7 @@
         String accessToken = node.at("/access_token").asText();
 
         // test list user group
-        response = resource().path(API_VERSION).path("group").path("list")
+        response = resource().path(API_VERSION).path("group")
                 .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
                 .get(ClientResponse.class);
 
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
index 1f1d874..0dff701 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
@@ -22,7 +22,6 @@
 import de.ids_mannheim.korap.constant.PredefinedRole;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.utils.JsonUtils;
-import de.ids_mannheim.korap.web.input.UserGroupJson;
 
 /**
  * @author margaretha
@@ -36,10 +35,10 @@
     private JsonNode listGroup (String username)
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
-        ClientResponse response = resource().path(API_VERSION).path("group").path("list")
-                .queryParam("username", username)
+        ClientResponse response = resource().path(API_VERSION).path("group")
                 .header(Attributes.AUTHORIZATION,
-                        HttpAuthorizationHandler.createBasicAuthorizationHeaderValue(
+                        HttpAuthorizationHandler
+                                .createBasicAuthorizationHeaderValue(
                                         testUsername, "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .get(ClientResponse.class);
@@ -93,9 +92,8 @@
     public void testListWithoutUsername () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
         ClientResponse response =
-                resource().path(API_VERSION).path("group").path("list")
-                        .header(Attributes.AUTHORIZATION,
-                                HttpAuthorizationHandler
+                resource().path(API_VERSION).path("group")
+                        .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                                         .createBasicAuthorizationHeaderValue(
                                                 adminUsername, "pass"))
                         .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -154,22 +152,22 @@
     public void testUserGroup () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
 
-        UserGroupJson json = new UserGroupJson();
         String groupName = "admin-test-group";
-        json.setName(groupName);
-        json.setMembers(new String[] { "marlin", "nemo" });
+        
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("members", "marlin,nemo");
 
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("create")
-                .type(MediaType.APPLICATION_JSON)
+                .path(groupName)
+                .type(MediaType.APPLICATION_FORM_URLENCODED)
                 .header(Attributes.AUTHORIZATION,
                         HttpAuthorizationHandler
                                 .createBasicAuthorizationHeaderValue(
                                         testUsername, "password"))
-                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").entity(json)
-                .post(ClientResponse.class);
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .entity(form).put(ClientResponse.class);
 
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
 
         // list user group
         JsonNode node = listGroup(testUsername);
@@ -188,15 +186,12 @@
             KustvaktException {
 
         // accept invitation
-        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
-        form.add("groupName", groupName);
-
         ClientResponse response = resource().path(API_VERSION).path("group")
                 .path(groupName).path("subscribe")
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue("marlin", "pass"))
-                .entity(form).post(ClientResponse.class);
+                        .createBasicAuthorizationHeaderValue(memberUsername, "pass"))
+                .post(ClientResponse.class);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
@@ -332,19 +327,18 @@
     private void testInviteMember (String groupName)
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
-        String[] members = new String[] { "darla" };
-
-        UserGroupJson userGroup = new UserGroupJson();
-        userGroup.setMembers(members);
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("members", "darla");
 
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path(groupName).path("invite").type(MediaType.APPLICATION_JSON)
+                .path(groupName).path("invite")
+                .type(MediaType.APPLICATION_FORM_URLENCODED)
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .header(Attributes.AUTHORIZATION,
                         HttpAuthorizationHandler
                                 .createBasicAuthorizationHeaderValue(
                                         adminUsername, "pass"))
-                .entity(userGroup).post(ClientResponse.class);
+                .entity(form).post(ClientResponse.class);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
index d538065..d81a3c3 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerTest.java
@@ -29,7 +29,6 @@
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.utils.JsonUtils;
-import de.ids_mannheim.korap.web.input.UserGroupJson;
 
 /**
  * @author margaretha
@@ -47,7 +46,6 @@
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("list")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username, "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -74,7 +72,6 @@
     @Test
     public void testListDoryGroups () throws KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("list")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("dory", "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -95,7 +92,6 @@
     @Test
     public void testListNemoGroups () throws KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("list")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("nemo", "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -116,7 +112,6 @@
     @Test
     public void testListMarlinGroups () throws KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("list").queryParam("username", "marlin")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("marlin", "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -130,7 +125,7 @@
     @Test
     public void testListGroupGuest () throws KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("list").header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .get(ClientResponse.class);
         String entity = response.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
@@ -147,11 +142,9 @@
     public void testCreateGroupEmptyMembers () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
         String groupName = "empty_group";
-        UserGroupJson json = new UserGroupJson();
-        json.setName(groupName);
-        json.setMembers(new String[] {});
-
-        testCreateUserGroup(json);
+        ClientResponse response = testCreateUserGroup(groupName,"");
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+        
         deleteGroupByName(groupName);
     }
 
@@ -160,56 +153,48 @@
     public void testCreateGroupMissingMembers () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
         String groupName = "missing-member-group";
-        UserGroupJson json = new UserGroupJson();
-        json.setName(groupName);
 
-        testCreateUserGroup(json);
+        ClientResponse response = testCreateGroupWithoutMembers(groupName);
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
         deleteGroupByName(groupName);
     }
     
-    private void testCreateUserGroup (UserGroupJson json) throws UniformInterfaceException,
-            ClientHandlerException, KustvaktException {
+    private ClientResponse testCreateUserGroup (String groupName, String members)
+            throws UniformInterfaceException, ClientHandlerException,
+            KustvaktException {
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("members", members);
+        
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("create").type(MediaType.APPLICATION_JSON)
+                .path(groupName).type(MediaType.APPLICATION_FORM_URLENCODED)
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username, "pass"))
-                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").entity(json)
-                .post(ClientResponse.class);
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").entity(form)
+                .put(ClientResponse.class);
 
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        return response;
     }
     
-    private void testCreateSameGroupName (UserGroupJson json)
+    private ClientResponse testCreateGroupWithoutMembers (String groupName)
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("create").type(MediaType.APPLICATION_JSON)
+                .path(groupName).type(MediaType.APPLICATION_FORM_URLENCODED)
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username, "pass"))
-                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").entity(json)
-                .post(ClientResponse.class);
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .put(ClientResponse.class);
 
-        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
-        
-        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
-        assertEquals(StatusCodes.GROUP_EXISTS, node.at("/errors/0/0").asInt());
+        return response;
     }
     
     @Test
     public void testCreateGroupInvalidName () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
-        UserGroupJson json = new UserGroupJson();
         String groupName = "invalid-group-name$"; 
-        json.setName(groupName);
-        json.setMembers(new String[] { "marlin", "nemo" });
+        String members = "marlin,nemo";
 
-        ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("create").type(MediaType.APPLICATION_JSON)
-                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue(username, "pass"))
-                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32").entity(json)
-                .post(ClientResponse.class);
-        
+        ClientResponse response = testCreateUserGroup(groupName, members);
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
         
         JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
@@ -223,20 +208,20 @@
     public void testUserGroup () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
 
-        UserGroupJson json = new UserGroupJson();
-        String groupName = "new-user-group"; 
-        json.setName(groupName);
-        json.setMembers(new String[] { "marlin", "nemo" });
+        String groupName = "new-user-group";
+        String members = "marlin,nemo";
 
-        testCreateUserGroup(json);
-        testCreateSameGroupName(json);
+        ClientResponse response = testCreateUserGroup(groupName,members);
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+        // same name
+        response = testCreateGroupWithoutMembers(groupName);
+        assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus());
 
         // list user group
         JsonNode node = retrieveUserGroups(username);;
         assertEquals(1, node.size());
         node = node.get(0);
         assertEquals("new-user-group", node.get("name").asText());
-        String groupId = node.get("id").asText();
 
         assertEquals(username, node.get("owner").asText());
         assertEquals(3, node.get("members").size());
@@ -275,7 +260,7 @@
                 .delete(ClientResponse.class);
 
         // check group member
-        response = resource().path(API_VERSION).path("group").path("list")
+        response = resource().path(API_VERSION).path("group")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username, "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -448,22 +433,21 @@
     private void testInviteMember (String groupName)
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
-        String[] members = new String[] { "darla" };
-
-        UserGroupJson userGroup = new UserGroupJson();
-        userGroup.setMembers(members);
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("members", "darla");
 
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path(groupName).path("invite").type(MediaType.APPLICATION_JSON)
+                .path(groupName).path("invite")
+                .type(MediaType.APPLICATION_FORM_URLENCODED)
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username, "pass"))
-                .entity(userGroup).post(ClientResponse.class);
+                .entity(form).post(ClientResponse.class);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
         // list group
-        response = resource().path(API_VERSION).path("group").path("list")
+        response = resource().path(API_VERSION).path("group")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue(username, "pass"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -483,17 +467,16 @@
 
     private void testInviteDeletedMember () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
-        String[] members = new String[] { "marlin" };
-
-        UserGroupJson userGroup = new UserGroupJson();
-        userGroup.setMembers(members);
-
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("members", "marlin");
+        
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("dory-group").path("invite").type(MediaType.APPLICATION_JSON)
+                .path("dory-group").path("invite")
+                .type(MediaType.APPLICATION_FORM_URLENCODED)
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("dory", "pass"))
-                .entity(userGroup).post(ClientResponse.class);
+                .entity(form).post(ClientResponse.class);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
@@ -510,17 +493,16 @@
     public void testInviteDeletedMember2 () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
         // pearl has status deleted in dory-group
-        String[] members = new String[] { "pearl" };
-
-        UserGroupJson userGroup = new UserGroupJson();
-        userGroup.setMembers(members);
-
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("members", "pearl");
+        
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("dory-group").path("invite").type(MediaType.APPLICATION_JSON)
+                .path("dory-group").path("invite")
+                .type(MediaType.APPLICATION_FORM_URLENCODED)
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("dory", "pass"))
-                .entity(userGroup).post(ClientResponse.class);
+                .entity(form).post(ClientResponse.class);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
@@ -538,17 +520,16 @@
     public void testInvitePendingMember () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
         // marlin has status PENDING in dory-group
-        String[] members = new String[] { "marlin" };
-
-        UserGroupJson userGroup = new UserGroupJson();
-        userGroup.setMembers(members);
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("members", "marlin");
 
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("dory-group").path("invite").type(MediaType.APPLICATION_JSON)
+                .path("dory-group").path("invite")
+                .type(MediaType.APPLICATION_FORM_URLENCODED)
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("dory", "pass"))
-                .entity(userGroup).post(ClientResponse.class);
+                .entity(form).post(ClientResponse.class);
         String entity = response.getEntity(String.class);
         // System.out.println(entity);
         JsonNode node = JsonUtils.readTree(entity);
@@ -567,17 +548,16 @@
     public void testInviteActiveMember () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
         // nemo has status active in dory-group
-        String[] members = new String[] { "nemo" };
-
-        UserGroupJson userGroup = new UserGroupJson();
-        userGroup.setMembers(members);
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("members", "nemo");
 
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("dory-group").path("invite").type(MediaType.APPLICATION_JSON)
+                .path("dory-group").path("invite")
+                .type(MediaType.APPLICATION_FORM_URLENCODED)
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("dory", "pass"))
-                .entity(userGroup).post(ClientResponse.class);
+                .entity(form).post(ClientResponse.class);
 
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
 
@@ -597,17 +577,16 @@
     public void testInviteMemberToDeletedGroup ()
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
-        String[] members = new String[] { "nemo" };
-
-        UserGroupJson userGroup = new UserGroupJson();
-        userGroup.setMembers(members);
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("members", "nemo");
 
         ClientResponse response = resource().path(API_VERSION).path("group")
-                .path("deleted-group").path("invite").type(MediaType.APPLICATION_JSON)
+                .path("deleted-group").path("invite")
+                .type(MediaType.APPLICATION_FORM_URLENCODED)
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
                         .createBasicAuthorizationHeaderValue("dory", "pass"))
-                .entity(userGroup).post(ClientResponse.class);
+                .entity(form).post(ClientResponse.class);
 
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());