Fixed bug: Uploading a new version of a versioned file with no quota left would leave...
[pithos] / src / gr / ebs / gss / server / domain / Folder.java
1 /*\r
2  * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.\r
3  *\r
4  * This file is part of GSS.\r
5  *\r
6  * GSS is free software: you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation, either version 3 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * GSS is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with GSS.  If not, see <http://www.gnu.org/licenses/>.\r
18  */\r
19 package gr.ebs.gss.server.domain;\r
20 \r
21 import gr.ebs.gss.server.domain.dto.FolderDTO;\r
22 \r
23 import java.io.Serializable;\r
24 import java.io.UnsupportedEncodingException;\r
25 import java.net.URLEncoder;\r
26 import java.util.ArrayList;\r
27 import java.util.HashSet;\r
28 import java.util.List;\r
29 import java.util.Set;\r
30 \r
31 import javax.persistence.CascadeType;\r
32 import javax.persistence.Column;\r
33 import javax.persistence.Embedded;\r
34 import javax.persistence.Entity;\r
35 import javax.persistence.GeneratedValue;\r
36 import javax.persistence.Id;\r
37 import javax.persistence.JoinColumn;\r
38 import javax.persistence.ManyToOne;\r
39 import javax.persistence.OneToMany;\r
40 import javax.persistence.OrderBy;\r
41 import javax.persistence.Version;\r
42 \r
43 /**\r
44  * The structure of a folder on the GSS service.\r
45  */\r
46 @Entity\r
47 public final class Folder  implements Serializable{\r
48 \r
49         /**\r
50          * The persistence ID of the object.\r
51          */\r
52         @Id\r
53         @GeneratedValue\r
54         private Long id;\r
55 \r
56         /**\r
57          * Version field for optimistic locking.\r
58          */\r
59         @SuppressWarnings("unused")\r
60         @Version\r
61         private int version;\r
62 \r
63         /**\r
64          * The audit information.\r
65          */\r
66         @Embedded\r
67         private AuditInfo auditInfo;\r
68 \r
69         /**\r
70          * The icon filename.\r
71          */\r
72         private String icon;\r
73 \r
74         /**\r
75          * The folder name.\r
76          */\r
77         private String name;\r
78 \r
79         /**\r
80          * The files in this folder. A List so we can keep order.\r
81          */\r
82         @OneToMany(cascade = CascadeType.ALL, mappedBy = "folder")\r
83         @OrderBy("name")\r
84         private List<FileHeader> files=new ArrayList<FileHeader>();\r
85 \r
86         /**\r
87          * The subfolders in this folder. A List so we can keep order.\r
88          */\r
89         @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")\r
90         @OrderBy("name")\r
91         private List<Folder> subfolders=new ArrayList<Folder>();\r
92 \r
93         /**\r
94          * The parent folder of this one.\r
95          */\r
96         @ManyToOne\r
97         private Folder parent;\r
98 \r
99         /**\r
100          * The owner of this folder.\r
101          */\r
102         @ManyToOne(optional=false)\r
103         @JoinColumn(nullable=false)\r
104         private User owner;\r
105 \r
106         /**\r
107          * Set of Permission objects: The permissions (User and Group) for this\r
108          * Folder.\r
109          */\r
110         @OneToMany(cascade = CascadeType.ALL)\r
111         private Set<Permission> permissions = new HashSet<Permission>();\r
112 \r
113 \r
114         /**\r
115          * Is this folder temporarily deleted?\r
116          */\r
117         @Column(columnDefinition=" boolean DEFAULT false")\r
118         private boolean deleted=false;\r
119         /**\r
120          * Retrieve the ID.\r
121          *\r
122          * @return the ID\r
123          */\r
124         public Long getId() {\r
125                 return id;\r
126         }\r
127 \r
128         /**\r
129          * Retrieve the icon.\r
130          *\r
131          * @return the icon\r
132          */\r
133         public String getIcon() {\r
134                 return icon;\r
135         }\r
136 \r
137         /**\r
138          * Replace the icon.\r
139          *\r
140          * @param newIcon the new icon\r
141          */\r
142         public void setIcon(final String newIcon) {\r
143                 icon = newIcon;\r
144         }\r
145 \r
146         /**\r
147          * Retrieve the folder name.\r
148          *\r
149          * @return the name\r
150          */\r
151         public String getName() {\r
152                 return name;\r
153         }\r
154 \r
155         /**\r
156          * Modify the folder name.\r
157          *\r
158          * @param newName the new name\r
159          */\r
160         public void setName(final String newName) {\r
161                 name = newName;\r
162         }\r
163 \r
164         /**\r
165          * Retrieve the list of files in the folder.\r
166          *\r
167          * @return a list of file header objects\r
168          */\r
169         public List<FileHeader> getFiles() {\r
170                 return files;\r
171         }\r
172 \r
173         /**\r
174          * Replace the list of files in the folder.\r
175          *\r
176          * @param newFiles the new list of files\r
177          */\r
178         public void setFiles(final List<FileHeader> newFiles) {\r
179                 files = newFiles;\r
180         }\r
181 \r
182         /**\r
183          * Retrieve the list of subfolders.\r
184          *\r
185          * @return the subfolders\r
186          */\r
187         public List<Folder> getSubfolders() {\r
188                 return subfolders;\r
189         }\r
190 \r
191         /**\r
192          * Replace the list of subfolders.\r
193          *\r
194          * @param newSubfolders the new subfolders\r
195          */\r
196         public void setSubfolders(final List<Folder> newSubfolders) {\r
197                 subfolders = newSubfolders;\r
198         }\r
199 \r
200         /**\r
201          * Retrieve the parent folder.\r
202          *\r
203          * @return the parent\r
204          */\r
205         public Folder getParent() {\r
206                 return parent;\r
207         }\r
208 \r
209         /**\r
210          * Replace the parent folder.\r
211          *\r
212          * @param newParent the new parent\r
213          */\r
214         public void setParent(final Folder newParent) {\r
215                 parent = newParent;\r
216         }\r
217 \r
218         /**\r
219          * Retrieve the owner.\r
220          *\r
221          * @return the owner\r
222          */\r
223         public User getOwner() {\r
224                 return owner;\r
225         }\r
226 \r
227         /**\r
228          * Modify the owner.\r
229          *\r
230          * @param newOwner the new owner\r
231          */\r
232         public void setOwner(final User newOwner) {\r
233                 owner = newOwner;\r
234         }\r
235 \r
236         /**\r
237          * Retrieve the audit info.\r
238          *\r
239          * @return the audit info\r
240          */\r
241         public AuditInfo getAuditInfo() {\r
242                 return auditInfo;\r
243         }\r
244 \r
245         /**\r
246          * Modify the audit info.\r
247          *\r
248          * @param newAuditInfo the new audit info\r
249          */\r
250         public void setAuditInfo(final AuditInfo newAuditInfo) {\r
251                 auditInfo = newAuditInfo;\r
252         }\r
253 \r
254         /**\r
255          * Retrieve the permission set.\r
256          *\r
257          * @return the permissions\r
258          */\r
259         public Set<Permission> getPermissions() {\r
260                 return permissions;\r
261         }\r
262 \r
263         /**\r
264          * Replace the permission set.\r
265          *\r
266          * @param newPermissions the new permissions\r
267          */\r
268         public void setPermissions(final Set<Permission> newPermissions) {\r
269                 permissions = newPermissions;\r
270         }\r
271 \r
272         /**\r
273          * Adds a subfolder to this folder. If the child already belongs to another\r
274          * parent folder, it is first removed from it.\r
275          *\r
276          * @param subfolder Folder to add\r
277          * @throws IllegalArgumentException if folder is null\r
278          */\r
279         public void addSubfolder(final Folder subfolder) {\r
280                 if (subfolder == null)\r
281                         throw new IllegalArgumentException("Can't add a null subfolder as a child.");\r
282                 // Remove from old parent folder\r
283                 if (subfolder.getParent() != null)\r
284                         subfolder.getParent().removeSubfolder(subfolder);\r
285                 // Set parent in child\r
286                 subfolder.setParent(this);\r
287                 // Set child in parent\r
288                 getSubfolders().add(subfolder);\r
289         }\r
290 \r
291         /**\r
292          * Removes a subfolder from this folder.\r
293          *\r
294          * @param subfolder Folder to remove\r
295          * @throws IllegalArgumentException if subfolder is null\r
296          */\r
297         public void removeSubfolder(final Folder subfolder) {\r
298                 if (subfolder == null)\r
299                         throw new IllegalArgumentException("Can't remove a null subfolder.");\r
300                 getSubfolders().remove(subfolder);\r
301                 subfolder.setParent(null);\r
302         }\r
303 \r
304         /**\r
305          * Adds a file to this folder. If the file already belongs to another parent\r
306          * folder, it is first removed from it.\r
307          *\r
308          * @param file FileHeader to add\r
309          * @throws IllegalArgumentException if file is null\r
310          */\r
311         public void addFile(final FileHeader file) {\r
312                 if (file == null)\r
313                         throw new IllegalArgumentException("Can't add a null file.");\r
314                 // Remove from old parent folder\r
315                 if (file.getFolder() != null)\r
316                         file.getFolder().removeFile(file);\r
317 \r
318                 getFiles().add(file);\r
319                 file.setFolder(this);\r
320         }\r
321 \r
322         /**\r
323          * Removes a file from this folder.\r
324          *\r
325          * @param file FileHeader to remove\r
326          * @throws IllegalArgumentException if file is null\r
327          */\r
328         public void removeFile(final FileHeader file) {\r
329                 if (file == null)\r
330                         throw new IllegalArgumentException("Can't remove a null file.");\r
331                 getFiles().remove(file);\r
332                 file.setFolder(null);\r
333         }\r
334 \r
335         /**\r
336          * Adds a permission to this Folder.\r
337          *\r
338          * @param permission Permission to add\r
339          * @throws IllegalArgumentException if permission is null\r
340          */\r
341         public void addPermission(final Permission permission) {\r
342                 if (permission == null)\r
343                         throw new IllegalArgumentException("Can't add a null Permission.");\r
344                 getPermissions().add(permission);\r
345         }\r
346 \r
347         /**\r
348          * Return the FolderDTO for this Folder object. The object graph that is\r
349          * constructed has maximum depth 2. This method is mainly intended for use\r
350          * by the web application interface.\r
351          *\r
352          * @return the FolderDTO that corresponds to this Folder\r
353          */\r
354         public FolderDTO getDTO() {\r
355                 return getDTO(2);\r
356         }\r
357 \r
358         /**\r
359          * Return the FolderDTO for this Folder object. The object graph that is\r
360          * constructed has the specified maximum depth and contains marked as deleted folders\r
361          *\r
362          * @param depth the maximum depth of the returned folder tree\r
363          * @return the FolderDTO that corresponds to this Folder\r
364          */\r
365         private FolderDTO getDTO(int depth) {\r
366                 FolderDTO f = new FolderDTO();\r
367                 f.setId(id);\r
368                 f.setName(name);\r
369                 f.setPath(getPath());\r
370                 f.setOwner(owner.getDTO());\r
371                 f.setAuditInfo(auditInfo.getDTO());\r
372                 f.setDeleted(deleted);\r
373                 if (parent != null)\r
374                         f.setParent(parent.getDTO(0));\r
375                 for (Folder subfolder : subfolders)\r
376                         if (depth > 0)\r
377                                 f.getSubfolders().add(subfolder.getDTO(depth - 1));\r
378                 return f;\r
379         }\r
380 \r
381         /**\r
382          * Checks if the specified user has permission to delete this folder, by\r
383          * checking if the user has write permission to the parent folder.\r
384          *\r
385          * @param user the specified User\r
386          * @return true if the user has permission to delete the folder, false\r
387          *         otherwise\r
388          */\r
389         public boolean hasDeletePermission(final User user) {\r
390                 if (parent.hasWritePermission(user))\r
391                         return true;\r
392                 return false;\r
393         }\r
394 \r
395         /**\r
396          * Checks if the specified user has permission to modify this folder.\r
397          *\r
398          * @param user the specified User\r
399          * @return true if the user has permission to modify the folder, false\r
400          *         otherwise\r
401          */\r
402         public boolean hasWritePermission(final User user) {\r
403                 for (final Permission p : permissions)\r
404                         if (p.getUser() != null) {\r
405                                 if (p.getUser().equals(user) && p.getWrite())\r
406                                         return true;\r
407                         } else if (p.getGroup().contains(user) && p.getWrite())\r
408                                 return true;\r
409                 return false;\r
410         }\r
411 \r
412         /**\r
413          * Checks if the specified user has permission to read this folder.\r
414          *\r
415          * @param user the specified User\r
416          * @return true if the user has permission to read the folder, false\r
417          *         otherwise\r
418          */\r
419         public boolean hasReadPermission(final User user) {\r
420                 for (final Permission p : permissions)\r
421                         if (p.getUser() != null) {\r
422                                 if (p.getUser().equals(user) && p.getRead())\r
423                                         return true;\r
424                         } else if (p.getGroup().contains(user) && p.getRead())\r
425                                 return true;\r
426                 return false;\r
427         }\r
428 \r
429         /**\r
430          * Checks if the specified user has permission to modify the ACL of this file.\r
431          *\r
432          * @param user the specified User\r
433          * @return true if the user has permission to modify the ACL of the file, false\r
434          *         otherwise\r
435          */\r
436         public boolean hasModifyACLPermission(final User user) {\r
437                 for (final Permission p : permissions)\r
438                         if (p.getUser() != null) {\r
439                                 if (p.getUser().equals(user) && p.getModifyACL())\r
440                                         return true;\r
441                         } else if (p.getGroup().contains(user) && p.getModifyACL())\r
442                                 return true;\r
443                 return false;\r
444         }\r
445 \r
446         /**\r
447          * Checks if the specified folder is shared (if it has permissions for other users and groups)\r
448          *\r
449          * @param user the specified User\r
450          * @return true if the user has permission to read the folder, false\r
451          *         otherwise\r
452          */\r
453         public boolean isShared(final User user) {\r
454                 for (final Permission p : permissions)\r
455                         if (p.getUser() != null) {\r
456                                 if (!p.getUser().equals(user))\r
457                                         return true;\r
458                         } else if (!p.getGroup().contains(user))\r
459                                 return true;\r
460                 return false;\r
461         }\r
462 \r
463         public boolean isSharedForOtherUser(final User user) {\r
464                 for (final Permission p : permissions)\r
465                         if (p.getUser() != null) {\r
466                                 if (p.getUser().equals(user))\r
467                                         return true;\r
468                         } else if (p.getGroup().contains(user))\r
469                                 return true;\r
470                 return false;\r
471         }\r
472 \r
473 \r
474         /**\r
475          * Retrieve the deleted.\r
476          *\r
477          * @return the deleted\r
478          */\r
479         public boolean isDeleted() {\r
480                 return deleted;\r
481         }\r
482 \r
483 \r
484         /**\r
485          * Modify the deleted.\r
486          *\r
487          * @param newDeleted the deleted to set\r
488          */\r
489         public void setDeleted(boolean newDeleted) {\r
490                 deleted = newDeleted;\r
491         }\r
492 \r
493         /**\r
494          * Retrieve the full path of the folder, URL-encoded in the form:\r
495          * /parent1/parent2/parent3/name\r
496          *\r
497          * @return the full path from the root of the files namespace\r
498          */\r
499         public String getPath() {\r
500                 if (parent == null)\r
501                         return "/";\r
502                 try {\r
503                         return parent.getPath() + URLEncoder.encode(name, "UTF-8") + '/';\r
504                 } catch (UnsupportedEncodingException e) {\r
505                         throw new RuntimeException(e);\r
506                 }\r
507         }\r
508 \r
509 }\r