Recall a faulty previous commit that was related to forbiding the uploading of a...
[pithos] / src / gr / ebs / gss / server / rest / GroupsHandler.java
1 /*
2  * Copyright 2008, 2009 Electronic Business Systems Ltd.
3  *
4  * This file is part of GSS.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19 package gr.ebs.gss.server.rest;
20
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;
28 import gr.ebs.gss.server.ejb.TransactionHelper;
29
30 import java.io.IOException;
31 import java.net.URLDecoder;
32 import java.net.URLEncoder;
33 import java.util.List;
34 import java.util.concurrent.Callable;
35
36 import javax.servlet.http.HttpServletRequest;
37 import javax.servlet.http.HttpServletResponse;
38
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41 import org.json.JSONArray;
42 import org.json.JSONException;
43 import org.json.JSONObject;
44
45
46 /**
47  * A class that handles operations on the 'groups' namespace.
48  *
49  * @author past
50  */
51 public class GroupsHandler extends RequestHandler {
52         /**
53          * The logger.
54          */
55         private static Log logger = LogFactory.getLog(GroupsHandler.class);
56
57     /**
58      * Serve the groups namespace for the user.
59      *
60      * @param req The servlet request we are processing
61      * @param resp The servlet response we are processing
62      * @throws IOException if an input/output error occurs
63          */
64         void serveGroups(HttpServletRequest req, HttpServletResponse resp) throws IOException {
65         String parentUrl = getContextPath(req, true);
66         String path = getInnerPath(req, PATH_GROUPS);
67                 if (path.equals(""))
68                         path = "/";
69
70         User user = getUser(req);
71         User owner = getOwner(req);
72         if (!owner.equals(user)) {
73                 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
74                 return;
75         }
76         if (path.equals("/"))
77                         // Request to serve all groups
78                 try {
79                 List<GroupDTO> groups = getService().getGroups(owner.getId());
80                 JSONArray json = new JSONArray();
81                 for (GroupDTO group: groups) {
82                         JSONObject j = new JSONObject();
83                         j.put("name", group.getName()).
84                                 put("uri", parentUrl + URLEncoder.encode(group.getName(),"UTF-8"));
85                                 json.put(j);
86                 }
87
88                 sendJson(req, resp, json.toString());
89                 } catch (ObjectNotFoundException e) {
90                         logger.error("User not found", e);
91                         resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
92                         return;
93                 } catch (RpcException e) {
94                         logger.error("", e);
95                         resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
96                         return;
97                 } catch (JSONException e) {
98                         logger.error("", e);
99                         resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
100                         return;
101                         }
102                 else {
103                 // Chop any trailing slash
104                 path = path.endsWith("/")? path.substring(0, path.length()-1): path;
105                 // Chop any leading slash
106                 path = path.startsWith("/")? path.substring(1): path;
107                 int slash = path.indexOf('/');
108                         try {
109                         if (slash != -1) {
110                                 // Request to serve group member
111                                 if (logger.isDebugEnabled())
112                                         logger.debug("Serving member " + path.substring(slash + 1) +
113                                                                 " from group " + path.substring(0, slash));
114                                 GroupDTO group = getService().getGroup(owner.getId(), URLDecoder.decode(path.substring(0, slash),"UTF-8"));
115                                 for (UserDTO 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());
123
124                                         sendJson(req, resp, json.toString());
125                                         }
126                         } else {
127                                 // Request to serve group
128                                 if (logger.isDebugEnabled())
129                                         logger.debug("Serving group " + path);
130                                 GroupDTO group = getService().getGroup(owner.getId(), URLDecoder.decode(path,"UTF-8"));
131                                 JSONArray json = new JSONArray();
132                                 for (UserDTO u: group.getMembers())
133                                         json.put(parentUrl + u.getUsername());
134
135                                 sendJson(req, resp, json.toString());
136                         }
137                         } catch (ObjectNotFoundException e) {
138                         logger.error("", e);
139                         resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
140                         return;
141                         } catch (RpcException e) {
142                         logger.error("", e);
143                         resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
144                         return;
145                         } catch (JSONException e) {
146                                 logger.error("", e);
147                                 resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
148                                 return;
149                         }
150         }
151         // Workaround for IE's broken caching behavior.
152                 resp.setHeader("Expires", "-1");
153         }
154
155         /**
156          * Handle POST requests in the groups namespace.
157          *
158      * @param req The servlet request we are processing
159      * @param resp The servlet response we are processing
160      * @throws IOException if an input/output error occurs
161          */
162         void postGroup(HttpServletRequest req, HttpServletResponse resp) throws IOException {
163         // Identify the requested resource path
164         String path = getInnerPath(req, PATH_GROUPS);
165                 if (path.equals(""))
166                         path = "/";
167
168                 try {
169                 User user = getUser(req);
170                 final User owner = getOwner(req);
171                 if (!owner.equals(user))
172                         throw new InsufficientPermissionsException("User " + user.getUsername()
173                                                 + " does not have permission to modify the groups owned by "
174                                                 + owner.getUsername());
175                 if (path.equals("/")) {
176                         // Request to add group
177                         final String group = req.getParameter(GROUP_PARAMETER);
178                         if (!isValidResourceName(group)) {
179                                 resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
180                                 return;
181                         }
182                         if (logger.isDebugEnabled())
183                                 logger.debug("Adding group " + group);
184                                 new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
185                                                 @Override
186                                                 public Void call() throws Exception {
187                                                         getService().createGroup(owner.getId(), group);
188                                                         return null;
189                                                 }
190                                         });
191                                 resp.setStatus(HttpServletResponse.SC_CREATED);
192                 } else {
193                         // Request to add group member
194                         String username = req.getParameter(USERNAME_PARAMETER);
195                         if (!isValidResourceName(username)) {
196                                 resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
197                                 return;
198                         }
199                         // Chop any trailing slash
200                         path = path.endsWith("/")? path.substring(0, path.length()-1): path;
201                         // Chop any leading slash
202                         path = path.startsWith("/")? path.substring(1): path;
203                         if (logger.isDebugEnabled())
204                                 logger.debug("Adding member " + username +
205                                                         " to group " + path);
206                         final GroupDTO group = getService().getGroup(owner.getId(), URLDecoder.decode(path,"UTF-8"));
207                         final User member = getService().findUser(username);
208                         if (member == null) {
209                                 resp.sendError(HttpServletResponse.SC_NOT_FOUND, "User " + username + " not found");
210                                 return;
211                         }
212                         new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
213                                         @Override
214                                         public Void call() throws Exception {
215                                                 getService().addUserToGroup(owner.getId(), group.getId(), member.getId());
216                                                 return null;
217                                         }
218                                 });
219                         resp.setStatus(HttpServletResponse.SC_CREATED);
220                 }
221                 // Workaround for IE's broken caching behavior.
222                         resp.setHeader("Expires", "-1");
223                 } catch (ObjectNotFoundException e) {
224                         resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
225                 } catch (IllegalArgumentException e) {
226                         resp.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
227                 } catch (DuplicateNameException e) {
228                         resp.sendError(HttpServletResponse.SC_CONFLICT, e.getMessage());
229                 } catch (RpcException e) {
230                         logger.error("", e);
231                         resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
232                 } catch (InsufficientPermissionsException e) {
233                         resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, e.getMessage());
234                 } catch (Exception e) {
235                         logger.error("", e);
236                         resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
237                 }
238
239         }
240
241         /**
242          * Handle DELETE requests in the groups namespace.
243          *
244      * @param req The servlet request we are processing
245      * @param resp The servlet response we are processing
246      * @throws IOException if an input/output error occurs
247          */
248         void deleteGroup(HttpServletRequest req, HttpServletResponse resp) throws IOException {
249         String path = getInnerPath(req, PATH_GROUPS);
250                 if (path.equals(""))
251                         path = "/";
252
253         if (path.equals("/"))
254                         resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, METHOD_GET + ", " + METHOD_POST);
255                 else {
256                 // Chop any trailing slash
257                 path = path.endsWith("/")? path.substring(0, path.length()-1): path;
258                 // Chop any leading slash
259                 path = path.startsWith("/")? path.substring(1): path;
260                 int slash = path.indexOf('/');
261                 try {
262                 User user = getUser(req);
263                 final User owner = getOwner(req);
264                 if (!owner.equals(user))
265                         throw new InsufficientPermissionsException("User " + user.getUsername()
266                                                 + " does not have permission to modify the groups owned by "
267                                                 + owner.getUsername());
268                 if (slash != -1) {
269                         // Request to delete group member
270                         if (logger.isDebugEnabled())
271                                 logger.debug("Removing member " + path.substring(slash + 1) +
272                                                         " from group " + path.substring(0, slash));
273                         final GroupDTO group = getService().getGroup(owner.getId(), URLDecoder.decode(path.substring(0, slash),"UTF-8"));
274                         for (final UserDTO u: group.getMembers())
275                                 if (u.getUsername().equals(path.substring(slash + 1)))
276                                         new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
277                                                 @Override
278                                                 public Void call() throws Exception {
279                                                         getService().removeMemberFromGroup(owner.getId(), group.getId(), u.getId());
280                                                         return null;
281                                                 }
282                                         });
283                 } else {
284                         if (logger.isDebugEnabled())
285                                 logger.debug("Removing group " + path);
286                                 final GroupDTO group = getService().getGroup(owner.getId(), URLDecoder.decode(path,"UTF-8"));
287                                 new TransactionHelper<Void>().tryExecute(new Callable<Void>() {
288                                         @Override
289                                         public Void call() throws Exception {
290                                                 getService().deleteGroup(owner.getId(), group.getId());
291                                                 return null;
292                                         }
293                                 });
294                 }
295                         resp.setStatus(HttpServletResponse.SC_NO_CONTENT);
296                         // Workaround for IE's broken caching behavior.
297                         resp.setHeader("Expires", "-1");
298                 } catch (RpcException e) {
299                         logger.error("", e);
300                         resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
301                 } catch (ObjectNotFoundException e) {
302                         resp.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
303                         } catch (InsufficientPermissionsException e) {
304                                 resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, e.getMessage());
305                         } catch (Exception e) {
306                         logger.error("", e);
307                         resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
308                         }
309         }
310         }
311
312 }