/*******************************************************************************
* Copyright (c) 2013 aegif.
*
* This file is part of NemakiWare.
*
* NemakiWare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NemakiWare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with NemakiWare.
* If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* linzhixing(https://github.com/linzhixing) - initial API and implementation
******************************************************************************/
package jp.aegif.nemaki.rest;
import jp.aegif.nemaki.common.ErrorCode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
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;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import jp.aegif.nemaki.businesslogic.PrincipalService;
import jp.aegif.nemaki.model.Group;
import jp.aegif.nemaki.model.User;
import org.apache.commons.lang.StringUtils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
@Path("/repo/{repositoryId}/group")
public class GroupResource extends ResourceBase{
PrincipalService principalService;
@SuppressWarnings("unchecked")
@GET
@Path("/search")
@Produces(MediaType.APPLICATION_JSON)
public String search(@PathParam("repositoryId") String repositoryId, @QueryParam("query") String query){
boolean status = true;
JSONObject result = new JSONObject();
JSONArray errMsg = new JSONArray();
List<Group> groups = this.principalService.getGroups(repositoryId);
JSONArray queriedGroups = new JSONArray();
for(Group g : groups) {
if ( g.getGroupId().startsWith(query)|| g.getName().startsWith(query)) {
queriedGroups.add(this.convertGroupToJson(g));
}
}
if( queriedGroups.size() == 0 ){
status = false;
addErrMsg(errMsg, ITEM_GROUP, ErrorCode.ERR_NOTFOUND);
}
else {
result.put("result", queriedGroups);
}
result = makeResult(status, result, errMsg);
return result.toString();
}
@SuppressWarnings("unchecked")
@GET
@Path("/list")
@Produces(MediaType.APPLICATION_JSON)
public String list(@PathParam("repositoryId") String repositoryId){
boolean status = true;
JSONObject result = new JSONObject();
JSONArray listJSON = new JSONArray();
JSONArray errMsg = new JSONArray();
List<Group> groupList;
try{
groupList = principalService.getGroups(repositoryId);
for(Group group : groupList){
JSONObject groupJSON = convertGroupToJson(group);
listJSON.add(groupJSON);
}
result.put(ITEM_ALLGROUPS, listJSON);
}catch(Exception ex){
ex.printStackTrace();
addErrMsg(errMsg, ITEM_ALLGROUPS, ErrorCode.ERR_LIST);
}
result = makeResult(status, result, errMsg);
return result.toString();
}
@SuppressWarnings("unchecked")
@GET
@Path("/show/{id}")
@Produces(MediaType.APPLICATION_JSON)
public String show(@PathParam("repositoryId") String repositoryId, @PathParam("id") String groupId){
boolean status = true;
JSONObject result = new JSONObject();
JSONArray errMsg = new JSONArray();
Group group = principalService.getGroupById(repositoryId, groupId);
if(group == null){
status = false;
addErrMsg(errMsg, ITEM_GROUP, ErrorCode.ERR_NOTFOUND);
}else{
result.put("group", convertGroupToJson(group));
}
makeResult(status, result, errMsg);
return result.toString();
}
@SuppressWarnings("unchecked")
@POST
@Path("/create/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String create(@PathParam("repositoryId") String repositoryId,
@PathParam("id") String groupId,
@FormParam(FORM_GROUPNAME) String name,
@FormParam("users") String users,
@FormParam("groups") String groups,
@Context HttpServletRequest httpRequest
){
boolean status = true;
JSONObject result = new JSONObject();
JSONArray errMsg = new JSONArray();
//Validation
status = validateNewGroup(repositoryId, status, errMsg, groupId, name);
//Edit group info
JSONArray _users = parseJsonArray(users);
JSONArray _groups = parseJsonArray(groups);
Group group = new Group(groupId, name, _users, _groups);
setFirstSignature(httpRequest, group);
//Create a group
if(status){
try{
principalService.createGroup(repositoryId, group);
}catch(Exception ex){
ex.printStackTrace();
status = false;
addErrMsg(errMsg, ITEM_GROUP, ErrorCode.ERR_CREATE);
}
}
result = makeResult(status, result, errMsg);
return result.toString();
}
@PUT
@Path("/update/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String update(@PathParam("repositoryId") String repositoryId,
@PathParam("id") String groupId,
@FormParam(FORM_GROUPNAME) String name,
@FormParam("users") String users,
@FormParam("groups") String groups,
@Context HttpServletRequest httpRequest){
boolean status = true;
JSONObject result = new JSONObject();
JSONArray errMsg = new JSONArray();
//Existing group
Group group = principalService.getGroupById(repositoryId, groupId);
//Validation
status = validateGroup(status, errMsg, groupId, name);
//Edit & Update
if(status){
//Edit group info
//if a parameter is not input, it won't be modified.
group.setName(name);
group.setUsers(parseJsonArray(users));
group.setGroups(parseJsonArray(groups));
setModifiedSignature(httpRequest, group);
try{
principalService.updateGroup(repositoryId, group);
}catch(Exception ex){
ex.printStackTrace();
status = false;
addErrMsg(errMsg, ITEM_GROUP, ErrorCode.ERR_UPDATE);
}
}
result = makeResult(status, result, errMsg);
return result.toString();
}
@DELETE
@Path("/delete/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String delete(@PathParam("repositoryId") String repositoryId,
@PathParam("id") String groupId){
boolean status = true;
JSONObject result = new JSONObject();
JSONArray errMsg = new JSONArray();
//Existing group
Group group = principalService.getGroupById(repositoryId, groupId);
if(group == null){
status = false;
addErrMsg(errMsg, ITEM_GROUP, ErrorCode.ERR_NOTFOUND);
}
//Delete the group
if(status){
try{
principalService.deleteGroup(repositoryId, group.getId());
}catch(Exception ex){
addErrMsg(errMsg, ITEM_GROUP, ErrorCode.ERR_DELETE);
}
}
result = makeResult(status, result, errMsg);
return result.toString();
}
@PUT
@Path("/{apiType: add|remove}/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String updateMembers(@PathParam("repositoryId") String repositoryId,
@PathParam("id") String groupId,
@PathParam("apiType") String apiType,
@FormParam(FORM_MEMBER_USERS) String users,
@FormParam(FORM_MEMBER_GROUPS) String groups,
@Context HttpServletRequest httpRequest){
boolean status = true;
JSONObject result = new JSONObject();
JSONArray errMsg = new JSONArray();
//Existing Group
Group group = principalService.getGroupById(repositoryId, groupId);
if(group == null){
status = false;
addErrMsg(errMsg, ITEM_GROUP, ErrorCode.ERR_NOTFOUND);
}
//Parse JSON string from input parameter
JSONArray usersAry = new JSONArray();
if(users != null){
try{
usersAry = (JSONArray)JSONValue.parseWithException(users); //JSON parse validation
}catch(Exception ex){
ex.printStackTrace();
status = false;
addErrMsg(errMsg, ITEM_MEMBER_USERS, ErrorCode.ERR_PARSEJSON);
}
}
JSONArray groupsAry = new JSONArray();
if(groups != null){
try{
groupsAry = (JSONArray)JSONValue.parseWithException(groups); //JSON parse validation
}catch(Exception ex){
ex.printStackTrace();
status = false;
addErrMsg(errMsg, ITEM_MEMBER_GROUPS, ErrorCode.ERR_PARSEJSON);
}
}
//Edit members info of the group
if(status){
//Group info
setModifiedSignature(httpRequest, group);
//Member(User) info
List<String> usersList = editUserMembers(repositoryId, usersAry, errMsg, apiType, group);
group.setUsers(usersList);
//Member(Group) info
List<String> groupsList = editGroupMembers(repositoryId, groupsAry, errMsg, apiType, group);
group.setGroups(groupsList);
//Update
if(apiType.equals(API_ADD)){
try{
principalService.updateGroup(repositoryId, group);
}catch(Exception ex){
ex.printStackTrace();
status = false;
addErrMsg(errMsg, ITEM_GROUP, ErrorCode.ERR_UPDATEMEMBERS);
}
}else if(apiType.equals(API_REMOVE)){
try{
principalService.updateGroup(repositoryId, group);
}catch(Exception ex){
ex.printStackTrace();
status = false;
addErrMsg(errMsg, ITEM_GROUP, ErrorCode.ERR_UPDATEMEMBERS);
}
}
}
result = makeResult(status, result, errMsg);
return result.toJSONString();
}
/**
*if list is null, return true.
* @param errMsg
* @param id
* @param list
* @return
*/
private boolean isNewRecord(JSONArray errMsg, String id, List<String> list){
boolean status = true;
if(list != null){
for (String s : list){
if(id.equals(s)){
status = false;
break;
}
}
}
return status;
}
/**
* edit group's members(users)
* @param repositoryId TODO
* @param usersAry
* @param errMsg
* @param apiType
* @param group
* @return
*/
private List<String> editUserMembers(String repositoryId, JSONArray usersAry, JSONArray errMsg, String apiType, Group group){
List<String> usersList = new ArrayList<String>();
List<String> ul = group.getUsers();
if(ul != null) usersList = ul;
for(final Object obj : usersAry){
boolean notSkip = true;
JSONObject objJSON = (JSONObject)obj;
String userId = (String)objJSON.get(FORM_ID);
//check only when "add" API
if(apiType.equals(API_ADD)){
User existingUser = principalService.getUserById(repositoryId, userId);
if(existingUser == null){
notSkip = false;
addErrMsg(errMsg, ITEM_USER + ":" + userId, ErrorCode.ERR_NOTFOUND);
}
}
if(notSkip){
//"add" method
if(apiType.equals(API_ADD)){
if(isNewRecord(errMsg, userId, usersList)){
usersList.add(userId);
}else{
addErrMsg(errMsg, ITEM_USER + ":" + userId, ErrorCode.ERR_ALREADYMEMBER);
}
//"remove" method
}else if(apiType.equals(API_REMOVE)){
if(!isNewRecord(errMsg, userId, usersList)){
usersList.remove(userId);
}else{
addErrMsg(errMsg, ITEM_USER + ":" + userId, ErrorCode.ERR_NOTMEMBER);
}
}
}
}
return usersList;
}
/**
* edit group's members(groups)
* @param repositoryId TODO
* @param groupsAry
* @param errMsg
* @param apiType
* @param group
* @return
*/
private List<String>editGroupMembers(String repositoryId, JSONArray groupsAry, JSONArray errMsg, String apiType, Group group){ //check only when "add" API
List<String>groupsList = new ArrayList<String>();
List<String> gl = group.getGroups();
if(gl != null) groupsList = gl;
List<Group> allGroupsList = principalService.getGroups(repositoryId);
List<String> allGroupsStringList = new ArrayList<String>();
for(final Group g : allGroupsList){
allGroupsStringList.add(g.getId());
}
for(final Object obj : groupsAry){
JSONObject objJSON = (JSONObject)obj;
String groupId = (String)objJSON.get(FORM_ID);
boolean notSkip = true;
//Existance check
Group g = principalService.getGroupById(repositoryId, groupId);
if(g == null && apiType.equals(API_ADD)){
notSkip = false;
addErrMsg(errMsg, ITEM_GROUP + ":" + groupId, ErrorCode.ERR_NOTFOUND);
}
if(notSkip){
//"add" method
if(apiType.equals(API_ADD)){
if(isNewRecord(errMsg, groupId, groupsList)){
if(groupId.equals(group.getId())){
//skip and error when trying to add the group to itself
addErrMsg(errMsg, ITEM_GROUP, ErrorCode.ERR_GROUPITSELF);
}else{
groupsList.add(groupId);
}
}else{
//skip and message
addErrMsg(errMsg, ITEM_GROUP + ":" + groupId, ErrorCode.ERR_ALREADYMEMBER);
}
//"remove" method
}else if(apiType.equals(API_REMOVE)){
if(!isNewRecord(errMsg, groupId, groupsList)){
groupsList.remove(groupId);
}else{
//skip
addErrMsg(errMsg, ITEM_GROUP + ":" + groupId, ErrorCode.ERR_NOTMEMBER);
}
}
}
}
return groupsList;
}
boolean validateNewGroup(String repositoryId, boolean status, JSONArray errMsg, String groupId, String name){
if(StringUtils.isBlank(groupId)){
status = false;
addErrMsg(errMsg, ITEM_GROUPID, ErrorCode.ERR_MANDATORY);
}
//groupID uniqueness
Group group = principalService.getGroupById(repositoryId, groupId);
if(group != null){
status = false;
addErrMsg(errMsg, ITEM_GROUPID, ErrorCode.ERR_ALREADYEXISTS);
}
if(StringUtils.isBlank(name)){
status = false;
addErrMsg(errMsg, ITEM_GROUPNAME, ErrorCode.ERR_MANDATORY);
}
return status;
}
boolean validateGroup(boolean status, JSONArray errMsg, String groupId, String name){
if(StringUtils.isBlank(name)){
status = false;
addErrMsg(errMsg, ITEM_GROUPNAME, ErrorCode.ERR_MANDATORY);
}
return status;
}
private JSONObject convertGroupToJson(Group group) {
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
String created = new String();
try{
created = sdf.format(group.getCreated().getTime());
}catch(Exception ex){
ex.printStackTrace();
}
String modified = new String();
try{
modified = sdf.format(group.getModified().getTime());
}catch(Exception ex){
ex.printStackTrace();
}
JSONObject groupJSON = new JSONObject();
groupJSON.put(ITEM_GROUPID, group.getGroupId());
groupJSON.put(ITEM_GROUPNAME, group.getName());
groupJSON.put(ITEM_CREATOR, group.getCreator());
groupJSON.put(ITEM_CREATED, created);
groupJSON.put(ITEM_MODIFIER, group.getModifier());
groupJSON.put(ITEM_MODIFIED, modified);
groupJSON.put(ITEM_TYPE, group.getType());
groupJSON.put(ITEM_MEMBER_USERS, group.getUsers());
groupJSON.put(ITEM_MEMBER_USERSSIZE, group.getUsers().size());
groupJSON.put(ITEM_MEMBER_GROUPS, group.getGroups());
groupJSON.put(ITEM_MEMBER_GROUPSSIZE, group.getGroups().size());
return groupJSON;
}
private JSONArray parseJsonArray(String str){
JSONParser parser = new JSONParser();
Object obj;
try {
obj = parser.parse(str);
JSONArray result = (JSONArray)obj;
return result;
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new JSONArray();
}
public void setPrincipalService(PrincipalService principalService) {
this.principalService = principalService;
}
}