2 * Copyright 2008, 2009 Electronic Business Systems Ltd.
4 * This file is part of GSS.
6 * GSS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GSS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GSS. If not, see <http://www.gnu.org/licenses/>.
19 package gr.ebs.gss.server.rest;
21 import gr.ebs.gss.client.exceptions.DuplicateNameException;
22 import gr.ebs.gss.client.exceptions.InsufficientPermissionsException;
23 import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
24 import gr.ebs.gss.client.exceptions.RpcException;
25 import gr.ebs.gss.server.domain.User;
26 import gr.ebs.gss.server.domain.dto.GroupDTO;
27 import gr.ebs.gss.server.domain.dto.UserDTO;
29 import java.io.IOException;
30 import java.net.URLDecoder;
31 import java.net.URLEncoder;
32 import java.util.List;
33 import java.util.concurrent.Callable;
35 import javax.servlet.http.HttpServletRequest;
36 import javax.servlet.http.HttpServletResponse;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.json.JSONArray;
41 import org.json.JSONException;
42 import org.json.JSONObject;
46 * A class that handles operations on the 'groups' namespace.
50 public class GroupsHandler extends RequestHandler {
54 private static Log logger = LogFactory.getLog(GroupsHandler.class);
57 * Serve the groups namespace for the user.
59 * @param req The servlet request we are processing
60 * @param resp The servlet response we are processing
61 * @throws IOException if an input/output error occurs
63 void serveGroups(HttpServletRequest req, HttpServletResponse resp) throws IOException {
64 String parentUrl = getContextPath(req, true);
65 String path = getInnerPath(req, PATH_GROUPS);
69 User user = getUser(req);
70 User owner = getOwner(req);
71 if (!owner.equals(user)) {
72 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
76 // Request to serve all groups
78 List<GroupDTO> groups = getService().getGroups(owner.getId());
79 JSONArray json = new JSONArray();
80 for (GroupDTO group: groups) {
81 JSONObject j = new JSONObject();
82 j.put("name", group.getName()).
83 put("uri", parentUrl + URLEncoder.encode(group.getName(),"UTF-8"));
87 sendJson(req, resp, json.toString());
88 } catch (ObjectNotFoundException e) {
89 logger.error("User not found", e);
90 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
92 } catch (RpcException e) {
94 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
96 } catch (JSONException e) {
98 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
102 // Chop any trailing slash
103 path = path.endsWith("/")? path.substring(0, path.length()-1): path;
104 // Chop any leading slash
105 path = path.startsWith("/")? path.substring(1): path;
106 int slash = path.indexOf('/');
109 // Request to serve group member
110 if (logger.isDebugEnabled())
111 logger.debug("Serving member " + path.substring(slash + 1) +
112 " from group " + path.substring(0, slash));
113 GroupDTO group = getService().getGroup(owner.getId(), URLDecoder.decode(path.substring(0, slash),"UTF-8"));
114 for (UserDTO u: group.getMembers())
115 if (u.getUsername().equals(path.substring(slash + 1))) {
116 // Build the proper parent URL
117 String pathInfo = req.getPathInfo();
118 parentUrl = parentUrl.replaceFirst(pathInfo, "");
119 JSONObject json = new JSONObject();
120 json.put("username", u.getUsername()).put("name", u.getName()).
121 put("home", parentUrl + u.getUsername());
123 sendJson(req, resp, json.toString());
126 // Request to serve group
127 if (logger.isDebugEnabled())
128 logger.debug("Serving group " + path);
129 GroupDTO group = getService().getGroup(owner.getId(), URLDecoder.decode(path,"UTF-8"));
130 JSONArray json = new JSONArray();
131 for (UserDTO u: group.getMembers())
132 json.put(parentUrl + u.getUsername());
134 sendJson(req, resp, json.toString());
136 } catch (ObjectNotFoundException e) {
138 resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
140 } catch (RpcException e) {
142 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
144 } catch (JSONException e) {
146 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
150 // Workaround for IE's broken caching behavior.
151 resp.setHeader("Expires", "-1");
155 * Handle POST requests in the groups namespace.
157 * @param req The servlet request we are processing
158 * @param resp The servlet response we are processing
159 * @throws IOException if an input/output error occurs
161 void postGroup(HttpServletRequest req, HttpServletResponse resp) throws IOException {
162 // Identify the requested resource path
163 String path = getInnerPath(req, PATH_GROUPS);
168 User user = getUser(req);
169 final User owner = getOwner(req);
170 if (!owner.equals(user))
171 throw new InsufficientPermissionsException("User " + user.getUsername()
172 + " does not have permission to modify the groups owned by "
173 + owner.getUsername());
174 if (path.equals("/")) {
175 // Request to add group
176 final String group = req.getParameter(GROUP_PARAMETER);
177 if (logger.isDebugEnabled())
178 logger.debug("Adding group " + group);
179 new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
181 public Void call() throws Exception {
182 getService().createGroup(owner.getId(), group);
186 resp.setStatus(HttpServletResponse.SC_CREATED);
188 // Request to add group member
189 String username = req.getParameter(USERNAME_PARAMETER);
190 // Chop any trailing slash
191 path = path.endsWith("/")? path.substring(0, path.length()-1): path;
192 // Chop any leading slash
193 path = path.startsWith("/")? path.substring(1): path;
194 if (logger.isDebugEnabled())
195 logger.debug("Adding member " + username +
196 " to group " + path);
197 final GroupDTO group = getService().getGroup(owner.getId(), URLDecoder.decode(path,"UTF-8"));
198 final User member = getService().findUser(username);
199 if (member == null) {
200 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "User " + username + " not found");
203 new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
205 public Void call() throws Exception {
206 getService().addUserToGroup(owner.getId(), group.getId(), member.getId());
210 resp.setStatus(HttpServletResponse.SC_CREATED);
212 // Workaround for IE's broken caching behavior.
213 resp.setHeader("Expires", "-1");
214 } catch (ObjectNotFoundException e) {
215 resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
216 } catch (IllegalArgumentException e) {
217 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
218 } catch (DuplicateNameException e) {
219 resp.sendError(HttpServletResponse.SC_CONFLICT, e.getMessage());
220 } catch (RpcException e) {
222 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
223 } catch (InsufficientPermissionsException e) {
224 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, e.getMessage());
225 } catch (Exception e) {
227 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
233 * Handle DELETE requests in the groups namespace.
235 * @param req The servlet request we are processing
236 * @param resp The servlet response we are processing
237 * @throws IOException if an input/output error occurs
239 void deleteGroup(HttpServletRequest req, HttpServletResponse resp) throws IOException {
240 String path = getInnerPath(req, PATH_GROUPS);
244 if (path.equals("/"))
245 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, METHOD_GET + ", " + METHOD_POST);
247 // Chop any trailing slash
248 path = path.endsWith("/")? path.substring(0, path.length()-1): path;
249 // Chop any leading slash
250 path = path.startsWith("/")? path.substring(1): path;
251 int slash = path.indexOf('/');
253 User user = getUser(req);
254 final User owner = getOwner(req);
255 if (!owner.equals(user))
256 throw new InsufficientPermissionsException("User " + user.getUsername()
257 + " does not have permission to modify the groups owned by "
258 + owner.getUsername());
260 // Request to delete group member
261 if (logger.isDebugEnabled())
262 logger.debug("Removing member " + path.substring(slash + 1) +
263 " from group " + path.substring(0, slash));
264 final GroupDTO group = getService().getGroup(owner.getId(), URLDecoder.decode(path.substring(0, slash),"UTF-8"));
265 for (final UserDTO u: group.getMembers())
266 if (u.getUsername().equals(path.substring(slash + 1)))
267 new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
269 public Void call() throws Exception {
270 getService().removeMemberFromGroup(owner.getId(), group.getId(), u.getId());
275 if (logger.isDebugEnabled())
276 logger.debug("Removing group " + path);
277 final GroupDTO group = getService().getGroup(owner.getId(), URLDecoder.decode(path,"UTF-8"));
278 new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
280 public Void call() throws Exception {
281 getService().deleteGroup(owner.getId(), group.getId());
286 resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
287 // Workaround for IE's broken caching behavior.
288 resp.setHeader("Expires", "-1");
289 } catch (RpcException e) {
291 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
292 } catch (ObjectNotFoundException e) {
293 resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
294 } catch (InsufficientPermissionsException e) {
295 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, e.getMessage());
296 } catch (Exception e) {
298 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);