Removed all DTO where possible
[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.FileHeaderDTO;\r
22 import gr.ebs.gss.server.domain.dto.FolderDTO;\r
23 \r
24 import java.io.Serializable;\r
25 import java.io.UnsupportedEncodingException;\r
26 import java.net.URLEncoder;\r
27 import java.util.ArrayList;\r
28 import java.util.HashSet;\r
29 import java.util.List;\r
30 import java.util.Set;\r
31 \r
32 import javax.persistence.CascadeType;\r
33 import javax.persistence.Column;\r
34 import javax.persistence.Embedded;\r
35 import javax.persistence.Entity;\r
36 import javax.persistence.GeneratedValue;\r
37 import javax.persistence.Id;\r
38 import javax.persistence.JoinColumn;\r
39 import javax.persistence.ManyToOne;\r
40 import javax.persistence.OneToMany;\r
41 import javax.persistence.OrderBy;\r
42 import javax.persistence.PrePersist;\r
43 import javax.persistence.PreUpdate;\r
44 import javax.persistence.Version;\r
45 \r
46 import org.hibernate.annotations.Cache;\r
47 import org.hibernate.annotations.CacheConcurrencyStrategy;\r
48 \r
49 /**\r
50  * The structure of a folder on the GSS service.\r
51  */\r
52 @Entity\r
53 @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)\r
54 public final class Folder  implements Serializable{\r
55 \r
56         /**\r
57          * The persistence ID of the object.\r
58          */\r
59         @Id\r
60         @GeneratedValue\r
61         private Long id;\r
62 \r
63         /**\r
64          * Version field for optimistic locking.\r
65          */\r
66         @SuppressWarnings("unused")\r
67         @Version\r
68         private int version;\r
69 \r
70         /**\r
71          * The audit information.\r
72          */\r
73         @Embedded\r
74         private AuditInfo auditInfo;\r
75 \r
76         /**\r
77          * The icon filename.\r
78          */\r
79         private String icon;\r
80 \r
81         /**\r
82          * The folder name.\r
83          */\r
84         private String name;\r
85 \r
86         /**\r
87          * The files in this folder. A List so we can keep order.\r
88          */\r
89         @OneToMany(cascade = CascadeType.ALL, mappedBy = "folder")\r
90         @OrderBy("name")\r
91         private List<FileHeader> files=new ArrayList<FileHeader>();\r
92 \r
93         /**\r
94          * The subfolders in this folder. A List so we can keep order.\r
95          */\r
96         @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent")\r
97         @OrderBy("name")\r
98         private List<Folder> subfolders=new ArrayList<Folder>();\r
99 \r
100         /**\r
101          * The parent folder of this one.\r
102          */\r
103         @ManyToOne\r
104         private Folder parent;\r
105 \r
106         /**\r
107          * The owner of this folder.\r
108          */\r
109         @ManyToOne(optional=false)\r
110         @JoinColumn(nullable=false)\r
111         private User owner;\r
112 \r
113         /**\r
114          * Set of Permission objects: The permissions (User and Group) for this\r
115          * Folder.\r
116          */\r
117         @OneToMany(cascade = CascadeType.ALL)\r
118         private Set<Permission> permissions = new HashSet<Permission>();\r
119 \r
120 \r
121         /**\r
122          * Is this folder temporarily deleted?\r
123          */\r
124         @Column(columnDefinition=" boolean DEFAULT false")\r
125         private boolean deleted=false;\r
126 \r
127         /**\r
128          * Can this folder be read by anyone?\r
129          * XXX: the columnDefinition is postgres specific, if deployment database is changed this shall be changed too\r
130          */\r
131         @Column(columnDefinition=" boolean DEFAULT false")\r
132         private boolean readForAll=false;\r
133         \r
134         @Column(columnDefinition=" boolean DEFAULT false")\r
135         private Boolean shared;\r
136 \r
137         /**\r
138          * Retrieve the ID.\r
139          *\r
140          * @return the ID\r
141          */\r
142         public Long getId() {\r
143                 return id;\r
144         }\r
145 \r
146         /**\r
147          * Retrieve the icon.\r
148          *\r
149          * @return the icon\r
150          */\r
151         public String getIcon() {\r
152                 return icon;\r
153         }\r
154 \r
155         /**\r
156          * Replace the icon.\r
157          *\r
158          * @param newIcon the new icon\r
159          */\r
160         public void setIcon(final String newIcon) {\r
161                 icon = newIcon;\r
162         }\r
163 \r
164         /**\r
165          * Retrieve the folder name.\r
166          *\r
167          * @return the name\r
168          */\r
169         public String getName() {\r
170                 return name;\r
171         }\r
172 \r
173         /**\r
174          * Modify the folder name.\r
175          *\r
176          * @param newName the new name\r
177          */\r
178         public void setName(final String newName) {\r
179                 name = newName;\r
180         }\r
181 \r
182         /**\r
183          * Retrieve the list of files in the folder.\r
184          *\r
185          * @return a list of file header objects\r
186          */\r
187         public List<FileHeader> getFiles() {\r
188                 return files;\r
189         }\r
190 \r
191         /**\r
192          * Replace the list of files in the folder.\r
193          *\r
194          * @param newFiles the new list of files\r
195          */\r
196         public void setFiles(final List<FileHeader> newFiles) {\r
197                 files = newFiles;\r
198         }\r
199 \r
200         /**\r
201          * Retrieve the list of subfolders.\r
202          *\r
203          * @return the subfolders\r
204          */\r
205         public List<Folder> getSubfolders() {\r
206                 return subfolders;\r
207         }\r
208 \r
209         /**\r
210          * Replace the list of subfolders.\r
211          *\r
212          * @param newSubfolders the new subfolders\r
213          */\r
214         public void setSubfolders(final List<Folder> newSubfolders) {\r
215                 subfolders = newSubfolders;\r
216         }\r
217 \r
218         /**\r
219          * Retrieve the parent folder.\r
220          *\r
221          * @return the parent\r
222          */\r
223         public Folder getParent() {\r
224                 return parent;\r
225         }\r
226 \r
227         /**\r
228          * Replace the parent folder.\r
229          *\r
230          * @param newParent the new parent\r
231          */\r
232         public void setParent(final Folder newParent) {\r
233                 parent = newParent;\r
234         }\r
235 \r
236         /**\r
237          * Retrieve the owner.\r
238          *\r
239          * @return the owner\r
240          */\r
241         public User getOwner() {\r
242                 return owner;\r
243         }\r
244 \r
245         /**\r
246          * Modify the owner.\r
247          *\r
248          * @param newOwner the new owner\r
249          */\r
250         public void setOwner(final User newOwner) {\r
251                 owner = newOwner;\r
252         }\r
253 \r
254         /**\r
255          * Retrieve the audit info.\r
256          *\r
257          * @return the audit info\r
258          */\r
259         public AuditInfo getAuditInfo() {\r
260                 return auditInfo;\r
261         }\r
262 \r
263         /**\r
264          * Modify the audit info.\r
265          *\r
266          * @param newAuditInfo the new audit info\r
267          */\r
268         public void setAuditInfo(final AuditInfo newAuditInfo) {\r
269                 auditInfo = newAuditInfo;\r
270         }\r
271 \r
272         /**\r
273          * Retrieve the permission set.\r
274          *\r
275          * @return the permissions\r
276          */\r
277         public Set<Permission> getPermissions() {\r
278                 return permissions;\r
279         }\r
280 \r
281         /**\r
282          * Replace the permission set.\r
283          *\r
284          * @param newPermissions the new permissions\r
285          */\r
286         public void setPermissions(final Set<Permission> newPermissions) {\r
287                 permissions = newPermissions;\r
288         }\r
289 \r
290         /**\r
291          * Adds a subfolder to this folder. If the child already belongs to another\r
292          * parent folder, it is first removed from it.\r
293          *\r
294          * @param subfolder Folder to add\r
295          * @throws IllegalArgumentException if folder is null\r
296          */\r
297         public void addSubfolder(final Folder subfolder) {\r
298                 if (subfolder == null)\r
299                         throw new IllegalArgumentException("Can't add a null subfolder as a child.");\r
300                 // Remove from old parent folder\r
301                 if (subfolder.getParent() != null)\r
302                         subfolder.getParent().removeSubfolder(subfolder);\r
303                 // Set parent in child\r
304                 subfolder.setParent(this);\r
305                 // Set child in parent\r
306                 getSubfolders().add(subfolder);\r
307         }\r
308 \r
309         /**\r
310          * Removes a subfolder from this folder.\r
311          *\r
312          * @param subfolder Folder to remove\r
313          * @throws IllegalArgumentException if subfolder is null\r
314          */\r
315         public void removeSubfolder(final Folder subfolder) {\r
316                 if (subfolder == null)\r
317                         throw new IllegalArgumentException("Can't remove a null subfolder.");\r
318                 getSubfolders().remove(subfolder);\r
319                 subfolder.setParent(null);\r
320         }\r
321 \r
322         /**\r
323          * Adds a file to this folder. If the file already belongs to another parent\r
324          * folder, it is first removed from it.\r
325          *\r
326          * @param file FileHeader to add\r
327          * @throws IllegalArgumentException if file is null\r
328          */\r
329         public void addFile(final FileHeader file) {\r
330                 if (file == null)\r
331                         throw new IllegalArgumentException("Can't add a null file.");\r
332                 // Remove from old parent folder\r
333                 if (file.getFolder() != null)\r
334                         file.getFolder().removeFile(file);\r
335 \r
336                 getFiles().add(file);\r
337                 file.setFolder(this);\r
338         }\r
339 \r
340         /**\r
341          * Removes a file from this folder.\r
342          *\r
343          * @param file FileHeader to remove\r
344          * @throws IllegalArgumentException if file is null\r
345          */\r
346         public void removeFile(final FileHeader file) {\r
347                 if (file == null)\r
348                         throw new IllegalArgumentException("Can't remove a null file.");\r
349                 getFiles().remove(file);\r
350                 file.setFolder(null);\r
351         }\r
352 \r
353         /**\r
354          * Adds a permission to this Folder.\r
355          *\r
356          * @param permission Permission to add\r
357          * @throws IllegalArgumentException if permission is null\r
358          */\r
359         public void addPermission(final Permission permission) {\r
360                 if (permission == null)\r
361                         throw new IllegalArgumentException("Can't add a null Permission.");\r
362                 getPermissions().add(permission);\r
363         }\r
364 \r
365         /**\r
366          * Return the FolderDTO for this Folder object. The object graph that is\r
367          * constructed has maximum depth 2. This method is mainly intended for use\r
368          * by the web application interface.\r
369          *\r
370          * @return the FolderDTO that corresponds to this Folder\r
371          */\r
372         public FolderDTO getDTO() {\r
373                 return getDTO(2);\r
374         }\r
375 \r
376         /**\r
377          * Return the FolderDTO for this Folder object. The object graph that is\r
378          * constructed has the specified maximum depth and contains marked as deleted folders\r
379          *\r
380          * @param depth the maximum depth of the returned folder tree\r
381          * @return the FolderDTO that corresponds to this Folder\r
382          */\r
383         private FolderDTO getDTO(int depth) {\r
384                 FolderDTO f = new FolderDTO();\r
385                 f.setId(id);\r
386                 f.setName(name);\r
387                 f.setPath(getPath());\r
388                 f.setOwner(owner.getDTO());\r
389                 f.setAuditInfo(auditInfo.getDTO());\r
390                 f.setDeleted(deleted);\r
391                 f.setReadForAll(readForAll);\r
392                 f.setShared(getShared());\r
393                 if (parent != null)\r
394                         f.setParent(parent.getDTO(0));\r
395                 for (Folder subfolder : subfolders)\r
396                         if (depth > 0)\r
397                                 f.getSubfolders().add(subfolder.getDTO(depth - 1));\r
398                 return f;\r
399         }\r
400 \r
401         /**\r
402          * Checks if the specified user has permission to delete this folder, by\r
403          * checking if the user has write permission to the parent folder.\r
404          *\r
405          * @param user the specified User\r
406          * @return true if the user has permission to delete the folder, false\r
407          *         otherwise\r
408          */\r
409         public boolean hasDeletePermission(final User user) {\r
410                 if (parent.hasWritePermission(user))\r
411                         return true;\r
412                 return false;\r
413         }\r
414 \r
415         /**\r
416          * Checks if the specified user has permission to modify this folder.\r
417          *\r
418          * @param user the specified User\r
419          * @return true if the user has permission to modify the folder, false\r
420          *         otherwise\r
421          */\r
422         public boolean hasWritePermission(final User user) {\r
423                 for (final Permission p : permissions)\r
424                         if (p.getUser() != null) {\r
425                                 if (p.getUser().equals(user) && p.getWrite())\r
426                                         return true;\r
427                         } else if (p.getGroup().contains(user) && p.getWrite())\r
428                                 return true;\r
429                 return false;\r
430         }\r
431 \r
432         /**\r
433          * Checks if the specified user has permission to read this folder.\r
434          *\r
435          * @param user the specified User\r
436          * @return true if the user has permission to read the folder, false\r
437          *         otherwise\r
438          */\r
439         public boolean hasReadPermission(final User user) {\r
440                 for (final Permission p : permissions)\r
441                         if (p.getUser() != null) {\r
442                                 if (p.getUser().equals(user) && p.getRead())\r
443                                         return true;\r
444                         } else if (p.getGroup().contains(user) && p.getRead())\r
445                                 return true;\r
446                 return false;\r
447         }\r
448 \r
449         /**\r
450          * Checks if the specified user has permission to modify the ACL of this file.\r
451          *\r
452          * @param user the specified User\r
453          * @return true if the user has permission to modify the ACL of the file, false\r
454          *         otherwise\r
455          */\r
456         public boolean hasModifyACLPermission(final User user) {\r
457                 for (final Permission p : permissions)\r
458                         if (p.getUser() != null) {\r
459                                 if (p.getUser().equals(user) && p.getModifyACL())\r
460                                         return true;\r
461                         } else if (p.getGroup().contains(user) && p.getModifyACL())\r
462                                 return true;\r
463                 return false;\r
464         }\r
465 \r
466         /**\r
467          * Checks if the specified folder is shared (if it has permissions for other users and groups)\r
468          *\r
469          * @param user the specified User\r
470          * @return true if the user has permission to read the folder, false\r
471          *         otherwise\r
472          */\r
473         public boolean isShared(final User user) {\r
474                 for (final Permission p : permissions)\r
475                         if (p.getUser() != null) {\r
476                                 if (!p.getUser().equals(user))\r
477                                         return true;\r
478                         } else if (!p.getGroup().contains(user))\r
479                                 return true;\r
480                 return false;\r
481         }\r
482 \r
483         public boolean isSharedForOtherUser(final User user) {\r
484                 for (final Permission p : permissions)\r
485                         if (p.getUser() != null) {\r
486                                 if (p.getUser().equals(user))\r
487                                         return true;\r
488                         } else if (p.getGroup().contains(user))\r
489                                 return true;\r
490                 return false;\r
491         }\r
492 \r
493 \r
494         /**\r
495          * Retrieve the deleted.\r
496          *\r
497          * @return the deleted\r
498          */\r
499         public boolean isDeleted() {\r
500                 return deleted;\r
501         }\r
502 \r
503 \r
504         /**\r
505          * Modify the deleted.\r
506          *\r
507          * @param newDeleted the deleted to set\r
508          */\r
509         public void setDeleted(boolean newDeleted) {\r
510                 deleted = newDeleted;\r
511         }\r
512 \r
513         /**\r
514          * Retrieve the full path of the folder, URL-encoded in the form:\r
515          * /parent1/parent2/parent3/name\r
516          *\r
517          * @return the full path from the root of the files namespace\r
518          */\r
519         public String getPath() {\r
520                 if (parent == null)\r
521                         return "/";\r
522                 try {\r
523                         return parent.getPath() + URLEncoder.encode(name, "UTF-8") + '/';\r
524                 } catch (UnsupportedEncodingException e) {\r
525                         throw new RuntimeException(e);\r
526                 }\r
527         }\r
528 \r
529         /**\r
530          * Modify the readForAll.\r
531          *\r
532          * @param newReadForAll the readForAll to set\r
533          */\r
534         public void setReadForAll(boolean newReadForAll) {\r
535                 readForAll = newReadForAll;\r
536         }\r
537 \r
538         /**\r
539          * Retrieve the readForAll.\r
540          *\r
541          * @return the readForAll\r
542          */\r
543         public boolean isReadForAll() {\r
544                 return readForAll;\r
545         }\r
546         \r
547         /**\r
548          * Retrieve the shared.\r
549          *\r
550          * @return the shared\r
551          */\r
552         public Boolean getShared() {\r
553                 if(shared==null)\r
554                         return false;\r
555                 return shared;\r
556         }\r
557         \r
558         \r
559         /**\r
560          * Modify the shared.\r
561          *\r
562          * @param shared the shared to set\r
563          */\r
564         public void setShared(Boolean shared) {\r
565                 this.shared = shared;\r
566         }\r
567         \r
568         @PrePersist\r
569         @PreUpdate\r
570         private void fixSharedFlag(){\r
571                 if(isReadForAll()||getPermissions().size()>1)\r
572                         shared=true;\r
573                 else\r
574                         shared=false;\r
575         }\r
576 \r
577         /**\r
578          * Retrieve the URI for this resource, relative to the REST API root URI.\r
579          * This unique identifier can be used to refer to the resource from\r
580          * various GSS clients.\r
581          *\r
582          * @return the URI\r
583          */\r
584         public String getURI() {\r
585                 return owner.getUsername() + FileHeader.PATH_FILES + getPath();\r
586         }\r
587 \r
588 \r
589 }\r