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.Group;
26 import gr.ebs.gss.server.domain.User;
27 import gr.ebs.gss.server.ejb.TransactionHelper;
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<Group> groups = getService().getGroups(owner.getId());
79 JSONArray json = new JSONArray();
80 for (Group 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 Group group = getService().getGroup(owner.getId(), URLDecoder.decode(path.substring(0, slash),"UTF-8"));
114 group = getService().expandGroup(group);
115 for (User u: group.getMembers())
116 if (u.getUsername().equals(path.substring(slash + 1))) {
117 // Build the proper parent URL
118 String pathInfo = req.getPathInfo();
119 parentUrl = parentUrl.replaceFirst(pathInfo, "");
120 JSONObject json = new JSONObject();
121 json.put("username", u.getUsername()).put("name", u.getName()).
122 put("home", parentUrl + u.getUsername());
124 sendJson(req, resp, json.toString());
127 // Request to serve group
128 if (logger.isDebugEnabled())
129 logger.debug("Serving group " + path);
130 Group group = getService().getGroup(owner.getId(), URLDecoder.decode(path,"UTF-8"));
131 group = getService().expandGroup(group);
132 JSONArray json = new JSONArray();
133 for (User u: group.getMembers())
134 json.put(parentUrl + u.getUsername());
136 sendJson(req, resp, json.toString());
138 } catch (ObjectNotFoundException e) {
140 resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
142 } catch (RpcException e) {
144 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
146 } catch (JSONException e) {
148 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
152 // Workaround for IE's broken caching behavior.
153 resp.setHeader("Expires", "-1");
157 * Handle POST requests in the groups namespace.
159 * @param req The servlet request we are processing
160 * @param resp The servlet response we are processing
161 * @throws IOException if an input/output error occurs
163 void postGroup(HttpServletRequest req, HttpServletResponse resp) throws IOException {
164 // Identify the requested resource path
165 String path = getInnerPath(req, PATH_GROUPS);
170 User user = getUser(req);
171 final User owner = getOwner(req);
172 if (!owner.equals(user))
173 throw new InsufficientPermissionsException("User " + user.getUsername()
174 + " does not have permission to modify the groups owned by "
175 + owner.getUsername());
176 if (path.equals("/")) {
177 // Request to add group
178 final String group = req.getParameter(GROUP_PARAMETER);
179 if (!isValidResourceName(group)) {
180 resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
183 if (logger.isDebugEnabled())
184 logger.debug("Adding group " + group);
185 new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
187 public Void call() throws Exception {
188 getService().createGroup(owner.getId(), group);
192 resp.setStatus(HttpServletResponse.SC_CREATED);
194 // Request to add group member
195 String username = req.getParameter(USERNAME_PARAMETER);
196 if (!isValidResourceName(username)) {
197 resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
200 // Chop any trailing slash
201 path = path.endsWith("/")? path.substring(0, path.length()-1): path;
202 // Chop any leading slash
203 path = path.startsWith("/")? path.substring(1): path;
204 if (logger.isDebugEnabled())
205 logger.debug("Adding member " + username +
206 " to group " + path);
207 final Group group = getService().getGroup(owner.getId(), URLDecoder.decode(path,"UTF-8"));
208 final User member = getService().findUser(username);
209 if (member == null) {
210 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "User " + username + " not found");
213 new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
215 public Void call() throws Exception {
216 getService().addUserToGroup(owner.getId(), group.getId(), member.getId());
220 resp.setStatus(HttpServletResponse.SC_CREATED);
222 // Workaround for IE's broken caching behavior.
223 resp.setHeader("Expires", "-1");
224 } catch (ObjectNotFoundException e) {
225 resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
226 } catch (IllegalArgumentException e) {
227 resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
228 } catch (DuplicateNameException e) {
229 resp.sendError(HttpServletResponse.SC_CONFLICT, e.getMessage());
230 } catch (RpcException e) {
232 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
233 } catch (InsufficientPermissionsException e) {
234 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, e.getMessage());
235 } catch (Exception e) {
237 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
243 * Handle DELETE requests in the groups namespace.
245 * @param req The servlet request we are processing
246 * @param resp The servlet response we are processing
247 * @throws IOException if an input/output error occurs
249 void deleteGroup(HttpServletRequest req, HttpServletResponse resp) throws IOException {
250 String path = getInnerPath(req, PATH_GROUPS);
254 if (path.equals("/"))
255 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, METHOD_GET + ", " + METHOD_POST);
257 // Chop any trailing slash
258 path = path.endsWith("/")? path.substring(0, path.length()-1): path;
259 // Chop any leading slash
260 path = path.startsWith("/")? path.substring(1): path;
261 int slash = path.indexOf('/');
263 User user = getUser(req);
264 final User owner = getOwner(req);
265 if (!owner.equals(user))
266 throw new InsufficientPermissionsException("User " + user.getUsername()
267 + " does not have permission to modify the groups owned by "
268 + owner.getUsername());
270 // Request to delete group member
271 if (logger.isDebugEnabled())
272 logger.debug("Removing member " + path.substring(slash + 1) +
273 " from group " + path.substring(0, slash));
274 final Group group = getService().getGroup(owner.getId(), URLDecoder.decode(path.substring(0, slash),"UTF-8"));
275 for (final User u: group.getMembers())
276 if (u.getUsername().equals(path.substring(slash + 1)))
277 new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
279 public Void call() throws Exception {
280 getService().removeMemberFromGroup(owner.getId(), group.getId(), u.getId());
285 if (logger.isDebugEnabled())
286 logger.debug("Removing group " + path);
287 final Group group = getService().getGroup(owner.getId(), URLDecoder.decode(path,"UTF-8"));
288 new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
290 public Void call() throws Exception {
291 getService().deleteGroup(owner.getId(), group.getId());
296 resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
297 // Workaround for IE's broken caching behavior.
298 resp.setHeader("Expires", "-1");
299 } catch (RpcException e) {
301 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
302 } catch (ObjectNotFoundException e) {
303 resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
304 } catch (InsufficientPermissionsException e) {
305 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, e.getMessage());
306 } catch (Exception e) {
308 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);