2 * Copyright 2007, 2008, 2009, 2010 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.ejb;
21 import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
22 import gr.ebs.gss.client.exceptions.DuplicateNameException;
23 import gr.ebs.gss.client.exceptions.GSSIOException;
24 import gr.ebs.gss.client.exceptions.InsufficientPermissionsException;
25 import gr.ebs.gss.client.exceptions.InvitationUsedException;
26 import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
27 import gr.ebs.gss.client.exceptions.QuotaExceededException;
28 import gr.ebs.gss.server.domain.AuditInfo;
29 import gr.ebs.gss.server.domain.FileBody;
30 import gr.ebs.gss.server.domain.FileHeader;
31 import gr.ebs.gss.server.domain.FileTag;
32 import gr.ebs.gss.server.domain.FileUploadStatus;
33 import gr.ebs.gss.server.domain.Folder;
34 import gr.ebs.gss.server.domain.Group;
35 import gr.ebs.gss.server.domain.Invitation;
36 import gr.ebs.gss.server.domain.Nonce;
37 import gr.ebs.gss.server.domain.Permission;
38 import gr.ebs.gss.server.domain.User;
39 import gr.ebs.gss.server.domain.UserClass;
40 import gr.ebs.gss.server.domain.dto.FileBodyDTO;
41 import gr.ebs.gss.server.domain.dto.FileHeaderDTO;
42 import gr.ebs.gss.server.domain.dto.FolderDTO;
43 import gr.ebs.gss.server.domain.dto.GroupDTO;
44 import gr.ebs.gss.server.domain.dto.PermissionDTO;
45 import gr.ebs.gss.server.domain.dto.StatsDTO;
46 import gr.ebs.gss.server.domain.dto.UserDTO;
49 import java.io.FileInputStream;
50 import java.io.FileNotFoundException;
51 import java.io.FileOutputStream;
52 import java.io.IOException;
53 import java.io.InputStream;
54 import java.io.StringWriter;
55 import java.io.UnsupportedEncodingException;
56 import java.util.ArrayList;
57 import java.util.Date;
58 import java.util.Iterator;
59 import java.util.LinkedHashSet;
60 import java.util.LinkedList;
61 import java.util.List;
62 import java.util.Locale;
63 import java.util.Random;
65 import java.util.StringTokenizer;
68 import javax.ejb.EJBException;
69 import javax.ejb.EJBTransactionRolledbackException;
70 import javax.ejb.Stateless;
71 import javax.ejb.TransactionAttribute;
72 import javax.ejb.TransactionAttributeType;
73 import javax.jms.Connection;
74 import javax.jms.ConnectionFactory;
75 import javax.jms.JMSException;
76 import javax.jms.MapMessage;
77 import javax.jms.MessageProducer;
78 import javax.jms.Queue;
79 import javax.jms.QueueConnectionFactory;
80 import javax.jms.Session;
81 import javax.naming.Context;
82 import javax.naming.InitialContext;
83 import javax.naming.NamingException;
84 import javax.persistence.PersistenceException;
85 import javax.xml.parsers.DocumentBuilder;
86 import javax.xml.parsers.DocumentBuilderFactory;
87 import javax.xml.parsers.ParserConfigurationException;
88 import javax.xml.transform.OutputKeys;
89 import javax.xml.transform.Transformer;
90 import javax.xml.transform.TransformerConfigurationException;
91 import javax.xml.transform.TransformerException;
92 import javax.xml.transform.TransformerFactory;
93 import javax.xml.transform.dom.DOMSource;
94 import javax.xml.transform.stream.StreamResult;
96 import org.apache.commons.httpclient.HttpClient;
97 import org.apache.commons.httpclient.HttpException;
98 import org.apache.commons.httpclient.NameValuePair;
99 import org.apache.commons.httpclient.methods.GetMethod;
100 import org.apache.commons.httpclient.methods.PostMethod;
101 import org.apache.commons.httpclient.methods.StringRequestEntity;
102 import org.apache.commons.lang.StringUtils;
103 import org.apache.commons.logging.Log;
104 import org.apache.commons.logging.LogFactory;
105 import org.hibernate.exception.ConstraintViolationException;
106 import org.w3c.dom.DOMException;
107 import org.w3c.dom.Document;
108 import org.w3c.dom.Node;
109 import org.w3c.dom.NodeList;
110 import org.xml.sax.SAXException;
112 import com.novell.ldap.LDAPAttribute;
113 import com.novell.ldap.LDAPAttributeSet;
114 import com.novell.ldap.LDAPConnection;
115 import com.novell.ldap.LDAPEntry;
116 import com.novell.ldap.LDAPException;
119 * The concrete implementation of the ExternalAPI interface.
124 public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
126 * The default MIME type for files without an explicit one.
128 private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
131 * The size of the buffer that is used to temporarily store chunks of
132 * uploaded files, while storing them to the file repository.
134 private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
139 private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
142 * Injected reference to the GSSDAO data access facade.
149 * A cached random number generator for creating unique filenames.
151 private static Random random = new Random();
154 * Mark the folder and all of its parent folders as modified from the specified user.
156 private void touchParentFolders(Folder folder, User user, Date date) {
159 AuditInfo ai = f.getAuditInfo();
160 ai.setModifiedBy(user);
161 ai.setModificationDate(date);
168 public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
170 throw new ObjectNotFoundException("No user specified");
171 Folder folder = dao.getRootFolder(userId);
172 return folder.getDTO();
176 public FolderDTO getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
178 throw new ObjectNotFoundException("No user specified");
179 if (folderId == null)
180 throw new ObjectNotFoundException("No folder specified");
181 final User user = dao.getEntityById(User.class, userId);
182 final Folder folder = dao.getEntityById(Folder.class, folderId);
184 if (!folder.hasReadPermission(user))
185 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
186 return folder.getDTO();
190 public User getUser(Long userId) throws ObjectNotFoundException {
192 throw new ObjectNotFoundException("No user specified");
193 return dao.getEntityById(User.class, userId);
197 public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
198 return getUser(userId).getDTO();
202 public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
204 throw new ObjectNotFoundException("No group specified");
205 final Group group = dao.getEntityById(Group.class, groupId);
206 return group.getDTO();
210 public GroupDTO getGroup(Long userId, String name) throws ObjectNotFoundException {
212 throw new ObjectNotFoundException("No user specified");
214 throw new ObjectNotFoundException("No group specified");
215 User user = dao.getEntityById(User.class, userId);
216 List<Group> groups = user.getGroupsSpecified();
217 for (Group group: groups)
218 if (group.getName().equals(name))
219 return group.getDTO();
220 throw new ObjectNotFoundException("Group " + name + " not found");
224 public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
226 throw new ObjectNotFoundException("No user specified");
227 final List<Group> groups = dao.getGroups(userId);
228 final List<GroupDTO> result = new ArrayList<GroupDTO>();
229 for (final Group g : groups)
230 result.add(g.getDTO());
235 public List<FileHeaderDTO> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
236 throws ObjectNotFoundException, InsufficientPermissionsException {
239 throw new ObjectNotFoundException("No user specified");
240 if (folderId == null)
241 throw new ObjectNotFoundException("No folder specified");
242 User user = dao.getEntityById(User.class, userId);
243 Folder folder = dao.getEntityById(Folder.class, folderId);
244 if (!folder.hasReadPermission(user))
245 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
246 // Do the actual work.
247 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
248 List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
249 for (FileHeader f : files)
250 result.add(f.getDTO());
255 public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
258 throw new ObjectNotFoundException("No user specified");
260 throw new ObjectNotFoundException("No group specified");
262 // Do the actual work.
263 final List<User> users = dao.getUsers(groupId);
264 final List<UserDTO> result = new ArrayList<UserDTO>();
265 for (final User u : users)
266 result.add(u.getDTO());
271 public FolderDTO createFolder(Long userId, Long parentId, String name)
272 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
275 throw new ObjectNotFoundException("No user specified");
276 if (StringUtils.isEmpty(name))
277 throw new ObjectNotFoundException("New folder name is empty");
278 if (parentId == null)
279 throw new ObjectNotFoundException("No parent specified");
280 if (dao.existsFolderOrFile(parentId, name))
281 throw new DuplicateNameException("A folder or file with the name '" +
282 name + "' already exists at this level");
284 User creator = dao.getEntityById(User.class, userId);
286 Folder parent = null;
288 parent = dao.getEntityById(Folder.class, parentId);
289 } catch (ObjectNotFoundException onfe) {
290 // Supply a more accurate problem description.
291 throw new ObjectNotFoundException("Parent folder not found");
293 if (!parent.hasWritePermission(creator))
294 throw new InsufficientPermissionsException("You don't have the permissions" +
295 " to write to this folder");
297 // Do the actual work.
298 return createFolder(name, parent, creator);
302 * Create a new folder with the provided name, parent and owner.
307 * @return the new folder
309 private FolderDTO createFolder(String name, Folder parent, User creator) {
310 Folder folder = new Folder();
311 folder.setName(name);
312 if (parent != null) {
313 parent.addSubfolder(folder);
314 folder.setOwner(parent.getOwner());
316 folder.setOwner(creator);
318 Date now = new Date();
319 AuditInfo auditInfo = new AuditInfo();
320 auditInfo.setCreatedBy(creator);
321 auditInfo.setCreationDate(now);
322 auditInfo.setModifiedBy(creator);
323 auditInfo.setModificationDate(now);
324 folder.setAuditInfo(auditInfo);
325 touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
328 for (Permission p : parent.getPermissions()) {
329 Permission permission = new Permission();
330 permission.setGroup(p.getGroup());
331 permission.setUser(p.getUser());
332 permission.setRead(p.getRead());
333 permission.setWrite(p.getWrite());
334 permission.setModifyACL(p.getModifyACL());
335 folder.addPermission(permission);
338 Permission permission = new Permission();
339 permission.setUser(creator);
340 permission.setRead(true);
341 permission.setWrite(true);
342 permission.setModifyACL(true);
343 folder.addPermission(permission);
347 folder.setReadForAll(parent.isReadForAll());
350 return folder.getDTO();
354 public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
357 throw new ObjectNotFoundException("No user specified");
358 if (folderId == null)
359 throw new ObjectNotFoundException("No folder specified");
361 // Do the actual work.
362 final Folder folder = dao.getEntityById(Folder.class, folderId);
363 final Folder parent = folder.getParent();
365 throw new ObjectNotFoundException("Deleting the root folder is not allowed");
366 final User user = dao.getEntityById(User.class, userId);
367 if (!folder.hasDeletePermission(user)) {
368 logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
369 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
371 removeSubfolderFiles(folder);
372 parent.removeSubfolder(folder);
374 touchParentFolders(parent, user, new Date());
378 * Traverses the folder and deletes all actual files (file system)
379 * regardless of permissions
383 private void removeSubfolderFiles(Folder folder) {
384 //remove files for all subfolders
385 for (Folder subfolder:folder.getSubfolders())
386 removeSubfolderFiles(subfolder);
387 //remove this folder's file bodies (actual files)
388 for (FileHeader file:folder.getFiles()) {
389 for (FileBody body:file.getBodies())
390 deleteActualFile(body.getStoredFilePath());
391 indexFile(file.getId(), true);
396 @SuppressWarnings("unchecked")
397 public List<FolderDTO> getSubfolders(Long userId, Long folderId)
398 throws ObjectNotFoundException, InsufficientPermissionsException {
400 throw new ObjectNotFoundException("No user specified");
401 if (folderId == null)
402 throw new ObjectNotFoundException("No folder specified");
403 User user = dao.getEntityById(User.class, userId);
404 Folder folder = dao.getEntityById(Folder.class, folderId);
405 if (!folder.hasReadPermission(user))
406 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
407 List<FolderDTO> result = new ArrayList<FolderDTO>();
408 if (folder.hasReadPermission(user))
409 for (Folder f : folder.getSubfolders())
410 if (f.hasReadPermission(user) && !f.isDeleted())
411 result.add(f.getDTO());
416 public FolderDTO updateFolder(Long userId, Long folderId, String folderName,
418 Set<PermissionDTO> permissions)
419 throws InsufficientPermissionsException, ObjectNotFoundException,
420 DuplicateNameException {
424 throw new ObjectNotFoundException("No user specified");
425 if (folderId == null)
426 throw new ObjectNotFoundException("No folder specified");
428 Folder folder = dao.getEntityById(Folder.class, folderId);
429 User user = dao.getEntityById(User.class, userId);
430 if (folderName != null && !folder.hasWritePermission(user))
431 throw new InsufficientPermissionsException("You don't have the necessary permissions");
432 if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
433 throw new InsufficientPermissionsException("You don't have the necessary permissions");
434 // Check permissions for making file public.
435 if (readForAll != null && !user.equals(folder.getOwner()))
436 throw new InsufficientPermissionsException("Only the owner can make a folder public or not public");
438 Folder parent = folder.getParent();
439 if (folderName != null) {
441 if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
442 throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
444 // Do the actual modification.
445 folder.setName(folderName);
447 if (permissions != null)
448 setFolderPermissions(user, folder, permissions);
449 if (readForAll != null)
450 setFolderReadForAll(user, folder, readForAll);
451 folder.getAuditInfo().setModificationDate(new Date());
452 folder.getAuditInfo().setModifiedBy(user);
454 touchParentFolders(folder, user, new Date());
455 return folder.getDTO();
459 public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
462 throw new ObjectNotFoundException("No user specified");
463 if (StringUtils.isEmpty(name))
464 throw new ObjectNotFoundException("New group name is empty");
465 if (name.indexOf('/')>=0)
466 throw new IllegalArgumentException("Character '/' is not allowed in group name");
467 if (dao.existsGroup(userId, name))
468 throw new DuplicateNameException("A group with the name '" + name + "' already exists");
470 // TODO: Check permissions
472 final User owner = dao.getEntityById(User.class, userId);
474 // Do the actual work.
475 owner.createGroup(name);
479 public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
482 throw new ObjectNotFoundException("No user specified");
484 throw new ObjectNotFoundException("No group specified");
486 // Do the actual work.
487 final User owner = dao.getEntityById(User.class, userId);
488 final Group group = dao.getEntityById(Group.class, groupId);
489 final Date now = new Date();
490 // Only delete the group if actually owned by the user.
491 if (group.getOwner().equals(owner)) {
492 List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
493 for (Folder f : folders){
494 f.getPermissions().removeAll(group.getPermissions());
495 touchFolder(f, owner, now);
496 for(FileHeader file : f.getFiles()){
497 file.getPermissions().removeAll(group.getPermissions());
498 touchFile(file, owner, now);
501 List<FileHeader> files = dao.getFilesPermittedForGroup(userId, groupId);
502 for(FileHeader h : files){
503 h.getPermissions().removeAll(group.getPermissions());
504 touchFile(h, owner, now);
506 owner.removeSpecifiedGroup(group);
509 else throw new InsufficientPermissionsException("You are not the owner of this group");
513 public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
514 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
515 InsufficientPermissionsException, QuotaExceededException {
518 file = uploadFile(stream, userId);
519 } catch ( IOException ioe) {
520 // Supply a more accurate problem description.
521 throw new GSSIOException("Problem creating file",ioe);
523 return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
527 * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
530 public void indexFile(Long fileId, boolean delete) {
531 Connection qConn = null;
532 Session session = null;
533 MessageProducer sender = null;
535 Context jndiCtx = new InitialContext();
536 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
537 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
538 qConn = factory.createConnection();
539 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
540 sender = session.createProducer(queue);
542 MapMessage map = session.createMapMessage();
543 map.setObject("id", fileId);
544 map.setBoolean("delete", delete);
547 catch (NamingException e) {
548 logger.error("Index was not updated: ", e);
550 catch (JMSException e) {
551 logger.error("Index was not updated: ", e);
562 catch (JMSException e) {
571 * A helper method that generates a unique file path for a stored file. The
572 * files are stored using random hash names that are distributed evenly in
573 * a 2-level tree of subdirectories named after the first two hex characters
574 * in the name. For example, file ab1234cd5769f will be stored in the path
575 * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
576 * if they don't already exist.
578 * @return a unique new file path
580 private String generateRepositoryFilePath() {
581 String filename = Long.toHexString(random.nextLong());
582 String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
583 File root = new File(fileRepositoryPath);
586 File firstFolder = new File(root + File.separator + filename.substring(0, 1));
587 if (!firstFolder.exists())
589 File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
590 if (!secondFolder.exists())
591 secondFolder.mkdir();
592 return secondFolder + File.separator + filename;
596 public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
599 throw new ObjectNotFoundException("No user specified");
601 throw new ObjectNotFoundException("No file specified");
603 // Do the actual work.
604 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
605 final Folder parent = file.getFolder();
607 throw new ObjectNotFoundException("The specified file has no parent folder");
608 final User user = dao.getEntityById(User.class, userId);
609 if (!file.hasDeletePermission(user))
610 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
611 for (final FileBody body : file.getBodies())
612 deleteActualFile(body.getStoredFilePath());
614 touchParentFolders(parent, user, new Date());
615 indexFile(fileId, true);
619 public void deleteActualFile(String path) {
622 File file = new File(path);
624 logger.error("Could not delete file " + path);
628 public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
630 throw new ObjectNotFoundException("No user specified");
631 if (fileHeaderId == null)
632 throw new ObjectNotFoundException("No file specified");
633 if (StringUtils.isEmpty(tag))
634 throw new ObjectNotFoundException("Tag is empty");
636 final User user = dao.getEntityById(User.class, userId);
637 final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
638 final Folder parent = fh.getFolder();
640 throw new ObjectNotFoundException("The specified file has no parent folder");
641 user.addTag(fh, tag);
642 touchParentFolders(parent, user, new Date());
646 public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
647 return dao.getUserTags(userId);
651 public void updateFile(Long userId, Long fileId, String name,
652 String tagSet, Date modificationDate, Boolean versioned,
653 Boolean readForAll, Set<PermissionDTO> permissions)
654 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
656 throw new ObjectNotFoundException("No user specified");
658 throw new ObjectNotFoundException("No file specified");
659 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
660 final Folder parent = file.getFolder();
662 throw new ObjectNotFoundException("The specified file has no parent folder");
664 User user = dao.getEntityById(User.class, userId);
665 // Check permissions for modifying the file metadata.
666 if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
667 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
668 // Check permissions for making file public.
669 if (readForAll != null && !user.equals(file.getOwner()))
670 throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
671 // Check permissions for modifying the ACL.
672 if(permissions != null && !permissions.isEmpty() && !file.hasModifyACLPermission(user))
673 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update the permissions on file " + file.getName() + "(" + file.getId() + ")");
676 // Do plain check for file already exists.
677 // Extreme concurrency case should be caught by constraint violation later.
678 if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
682 if (modificationDate != null)
683 file.getAuditInfo().setModificationDate(modificationDate);
685 file.getAuditInfo().setModificationDate(new Date());
686 file.getAuditInfo().setModifiedBy(user);
688 List<FileTag> tags = file.getFileTags();
689 if (tagSet != null) {
690 Iterator<FileTag> i = tags.iterator();
691 while (i.hasNext()) {
692 FileTag tag = i.next();
699 StringTokenizer st = new StringTokenizer(tagSet, ",");
700 while (st.hasMoreTokens())
701 new FileTag(user, file, st.nextToken().trim());
703 if (versioned != null && !file.isVersioned() == versioned) {
704 if (file.isVersioned())
705 removeOldVersions(userId, fileId);
706 file.setVersioned(versioned);
708 if (readForAll != null && user.equals(file.getOwner()))
709 file.setReadForAll(readForAll);
710 if (permissions != null && !permissions.isEmpty())
711 setFilePermissions(file, permissions);
714 * Force constraint violation to manifest itself here.
715 * This should cover extreme concurrency cases that the simple check
716 * above hasn't caught.
721 catch (EJBTransactionRolledbackException e) {
722 Throwable cause = e.getCause();
723 if (cause instanceof PersistenceException && cause.getCause() instanceof ConstraintViolationException)
724 throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
728 touchParentFolders(parent, user, new Date());
730 // Re-index the file if it was modified.
731 if (name != null || tagSet != null)
732 indexFile(fileId, false);
736 public InputStream getFileContents(Long userId, Long fileId)
737 throws ObjectNotFoundException, InsufficientPermissionsException {
739 throw new ObjectNotFoundException("No user specified");
741 throw new ObjectNotFoundException("No file specified");
743 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
744 User user = dao.getEntityById(User.class, userId);
745 if (!header.hasReadPermission(user)) {
746 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
747 throw new InsufficientPermissionsException("You don't have the necessary permissions");
750 File f = new File(header.getCurrentBody().getStoredFilePath());
752 return new FileInputStream(f);
753 } catch (FileNotFoundException e) {
754 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
755 throw new ObjectNotFoundException("The file contents could not be located");
760 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
763 public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
765 throw new ObjectNotFoundException("No user specified");
767 throw new ObjectNotFoundException("No file specified");
769 throw new ObjectNotFoundException("No file specified");
771 final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
772 final FileBody body = dao.getEntityById(FileBody.class, bodyId);
773 final User user = dao.getEntityById(User.class, userId);
774 if (!header.hasReadPermission(user)) {
775 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
776 throw new InsufficientPermissionsException("You don't have the necessary permissions");
779 File f = new File(body.getStoredFilePath());
781 return new FileInputStream(f);
782 } catch (FileNotFoundException e) {
783 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
784 throw new ObjectNotFoundException("The file contents could not be located");
789 public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
791 throw new ObjectNotFoundException("No user specified");
793 throw new ObjectNotFoundException("No file specified");
794 final User user = dao.getEntityById(User.class, userId);
795 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
796 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
797 throw new InsufficientPermissionsException("You don't have the necessary permissions");
798 return file.getDTO();
802 public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
804 throw new ObjectNotFoundException("No user specified");
806 throw new ObjectNotFoundException("No file specified");
807 User user = dao.getEntityById(User.class, userId);
808 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
809 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
810 throw new InsufficientPermissionsException("You don't have the necessary permissions");
811 FileBody body = dao.getEntityById(FileBody.class, bodyId);
812 return body.getDTO();
816 public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
817 throws ObjectNotFoundException {
819 throw new ObjectNotFoundException("No user specified");
820 if (StringUtils.isEmpty(path))
821 throw new ObjectNotFoundException("No path specified");
823 User owner = dao.getEntityById(User.class, ownerId);
824 List<String> pathElements = new ArrayList<String>();
825 StringTokenizer st = new StringTokenizer(path, "/");
826 while (st.hasMoreTokens())
827 pathElements.add(st.nextToken());
828 if (pathElements.size() < 1)
829 return getRootFolder(owner.getId());
830 // Store the last element, since it requires special handling.
831 String lastElement = pathElements.remove(pathElements.size() - 1);
832 FolderDTO cursor = getRootFolder(owner.getId());
833 // Traverse and verify the specified folder path.
834 for (String pathElement : pathElements) {
835 cursor = getFolder(cursor.getId(), pathElement);
836 if (cursor.isDeleted())
837 throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
840 // Use the lastElement to retrieve the actual resource.
841 Object resource = null;
843 FileHeaderDTO file = getFile(cursor.getId(), lastElement);
844 if (ignoreDeleted && file.isDeleted())
845 throw new ObjectNotFoundException("Resource not found");
847 } catch (ObjectNotFoundException e) {
848 // Perhaps the requested resource is not a file, so
849 // check for folders as well.
850 FolderDTO folder = getFolder(cursor.getId(), lastElement);
851 if (ignoreDeleted && folder.isDeleted())
852 throw new ObjectNotFoundException("Resource not found");
859 * Retrieve a file for the specified user that has the specified name and
860 * its parent folder has id equal to folderId.
862 * @param userId the ID of the current user
863 * @param folderId the ID of the parent folder
864 * @param name the name of the requested file
865 * @return the file found
866 * @throws ObjectNotFoundException if the specified folder or file was not
867 * found, with the exception message mentioning the precise
870 private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
871 if (folderId == null)
872 throw new ObjectNotFoundException("No parent folder specified");
873 if (StringUtils.isEmpty(name))
874 throw new ObjectNotFoundException("No file specified");
876 FileHeader file = dao.getFile(folderId, name);
877 return file.getDTO();
881 * Retrieve a folder for the specified user that has the specified name and
882 * its parent folder has id equal to parentId.
884 * @param parentId the ID of the parent folder
885 * @param name the name of the requested folder
886 * @return the folder found
887 * @throws ObjectNotFoundException if the specified folder or parent was not
888 * found, with the exception message mentioning the precise
891 private FolderDTO getFolder(Long parentId, String name) throws ObjectNotFoundException {
892 if (parentId == null)
893 throw new ObjectNotFoundException("No parent folder specified");
894 if (StringUtils.isEmpty(name))
895 throw new ObjectNotFoundException("No folder specified");
897 Folder folder = dao.getFolder(parentId, name);
898 return folder.getDTO();
901 private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
904 file = uploadFile(resourceInputStream, userId);
905 } catch ( IOException ioe) {
906 // Supply a more accurate problem description.
907 throw new GSSIOException("Problem creating file",ioe);
909 return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
913 public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
915 throw new ObjectNotFoundException("No user specified");
917 throw new ObjectNotFoundException("No file specified");
918 if (StringUtils.isEmpty(dest))
919 throw new ObjectNotFoundException("No destination specified");
921 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
922 if (!(destination instanceof FolderDTO))
923 throw new ObjectNotFoundException("Destination parent folder not found");
924 FolderDTO parent = (FolderDTO) destination;
925 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
929 public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
931 throw new ObjectNotFoundException("No user specified");
933 throw new ObjectNotFoundException("No owner specified");
935 throw new ObjectNotFoundException("No file specified");
936 if (StringUtils.isEmpty(dest))
937 throw new ObjectNotFoundException("No destination specified");
939 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
940 if (!(destination instanceof FolderDTO))
941 throw new ObjectNotFoundException("Destination parent folder not found");
942 FolderDTO parent = (FolderDTO) destination;
943 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
947 public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
949 throw new ObjectNotFoundException("No user specified");
951 throw new ObjectNotFoundException("No file specified");
953 throw new ObjectNotFoundException("No destination specified");
954 if (StringUtils.isEmpty(destName))
955 throw new ObjectNotFoundException("No destination file name specified");
957 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
958 Folder destination = dao.getEntityById(Folder.class, destId);
959 User user = dao.getEntityById(User.class, userId);
960 if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
961 throw new InsufficientPermissionsException("You don't have the necessary permissions");
962 boolean versioned = file.isVersioned();
963 int versionsNumber = file.getBodies().size();
964 FileBody oldestBody = file.getBodies().get(0);
965 assert oldestBody != null;
966 File contents = new File(oldestBody.getStoredFilePath());
968 createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
969 FileHeader copiedFile = dao.getFile(destination.getId(), destName);
970 copiedFile.setVersioned(versioned);
972 if (versionsNumber > 1)
973 for (int i = 1; i < versionsNumber; i++) {
974 FileBody body = file.getBodies().get(i);
976 contents = new File(body.getStoredFilePath());
977 updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
979 List<FileTag> tags = file.getFileTags();
980 for (FileTag tag : tags)
981 createTag(userId, copiedFile.getId(), tag.getTag());
983 } catch (FileNotFoundException e) {
984 throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
990 public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
992 throw new ObjectNotFoundException("No user specified");
993 if (folderId == null)
994 throw new ObjectNotFoundException("No folder specified");
995 if (StringUtils.isEmpty(dest))
996 throw new ObjectNotFoundException("No destination specified");
998 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
999 if (!(destination instanceof FolderDTO))
1000 throw new ObjectNotFoundException("Destination folder not found");
1001 FolderDTO parent = (FolderDTO) destination;
1002 copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
1006 public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1008 throw new ObjectNotFoundException("No user specified");
1009 if (folderId == null)
1010 throw new ObjectNotFoundException("No folder specified");
1012 throw new ObjectNotFoundException("No destination specified");
1013 if (StringUtils.isEmpty(destName))
1014 throw new ObjectNotFoundException("No destination folder name specified");
1015 Folder folder = dao.getEntityById(Folder.class, folderId);
1016 Folder destination = dao.getEntityById(Folder.class, destId);
1017 User user = dao.getEntityById(User.class, userId);
1018 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1019 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1020 createFolder(user.getId(), destination.getId(), destName);
1024 public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1026 throw new ObjectNotFoundException("No user specified");
1027 if (ownerId == null)
1028 throw new ObjectNotFoundException("No owner specified");
1029 if (folderId == null)
1030 throw new ObjectNotFoundException("No folder specified");
1031 if (StringUtils.isEmpty(dest))
1032 throw new ObjectNotFoundException("No destination specified");
1034 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1035 if (!(destination instanceof FolderDTO))
1036 throw new ObjectNotFoundException("Destination folder not found");
1037 FolderDTO parent = (FolderDTO) destination;
1038 copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1042 public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1044 throw new ObjectNotFoundException("No user specified");
1045 if (folderId == null)
1046 throw new ObjectNotFoundException("No folder specified");
1048 throw new ObjectNotFoundException("No destination specified");
1049 if (StringUtils.isEmpty(destName))
1050 throw new ObjectNotFoundException("No destination folder name specified");
1052 Folder folder = dao.getEntityById(Folder.class, folderId);
1053 Folder destination = dao.getEntityById(Folder.class, destId);
1054 final User user = dao.getEntityById(User.class, userId);
1055 // XXX: quick fix need to copy only visible items to user (Source
1057 if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1059 if(folder.isDeleted())//do not copy trashed folder and contents
1061 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1062 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1063 createFolder(user.getId(), destination.getId(), destName);
1064 Folder createdFolder = dao.getFolder(destination.getId(), destName);
1065 List<FileHeader> files = folder.getFiles();
1067 for (FileHeader file : files)
1068 if(!file.isDeleted())
1069 copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1070 List<Folder> subFolders = folder.getSubfolders();
1071 if (subFolders != null)
1072 for (Folder sub : subFolders)
1073 if(!sub.getId().equals(createdFolder.getId()))
1074 copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1079 * For a provided path, remove the last element and return the rest, that is
1080 * the path of the parent folder.
1082 * @param path the specified path
1083 * @return the path of the parent folder
1084 * @throws ObjectNotFoundException if the provided string contains no path
1087 private String getParentPath(String path) throws ObjectNotFoundException {
1088 int lastDelimiter = path.lastIndexOf('/');
1089 if (lastDelimiter == 0)
1091 if (lastDelimiter == -1)
1093 throw new ObjectNotFoundException("There is no parent in the path: " + path);
1094 else if (lastDelimiter < path.length() - 1)
1095 // Return the part before the delimiter.
1096 return path.substring(0, lastDelimiter);
1098 // Remove the trailing delimiter and then recurse.
1099 String strippedTrail = path.substring(0, lastDelimiter);
1100 return getParentPath(strippedTrail);
1105 * Get the last element in a path that denotes the file or folder name.
1107 * @param path the provided path
1108 * @return the last element in the path
1110 private String getLastElement(String path) {
1111 int lastDelimiter = path.lastIndexOf('/');
1112 if (lastDelimiter == -1)
1115 else if (lastDelimiter < path.length() - 1)
1116 // Return the part after the delimiter.
1117 return path.substring(lastDelimiter + 1);
1119 // Remove the trailing delimiter and then recurse.
1120 String strippedTrail = path.substring(0, lastDelimiter);
1121 return getLastElement(strippedTrail);
1126 public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1128 throw new ObjectNotFoundException("No user specified");
1130 throw new ObjectNotFoundException("No file specified");
1132 // Do the actual work.
1133 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1134 Folder parent = file.getFolder();
1136 throw new ObjectNotFoundException("The specified file has no parent folder");
1137 User user = dao.getEntityById(User.class, userId);
1138 if (!file.hasDeletePermission(user))
1139 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1141 file.setDeleted(true);
1143 touchParentFolders(parent, user, new Date());
1147 public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1149 throw new ObjectNotFoundException("No user specified");
1150 if (ownerId == null)
1151 throw new ObjectNotFoundException("No owner specified");
1153 throw new ObjectNotFoundException("No file specified");
1154 if (StringUtils.isEmpty(dest))
1155 throw new ObjectNotFoundException("No destination specified");
1157 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1158 if (!(destination instanceof FolderDTO))
1159 throw new ObjectNotFoundException("Destination parent folder not found");
1160 FolderDTO parent = (FolderDTO) destination;
1161 moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1165 public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1167 throw new ObjectNotFoundException("No user specified");
1169 throw new ObjectNotFoundException("No file specified");
1171 throw new ObjectNotFoundException("No destination specified");
1172 if (StringUtils.isEmpty(destName))
1173 throw new ObjectNotFoundException("No destination file name specified");
1175 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1176 Folder source = file.getFolder();
1177 Folder destination = dao.getEntityById(Folder.class, destId);
1179 User owner = dao.getEntityById(User.class, userId);
1180 if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1181 throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1183 // if the destination folder belongs to another user:
1184 if (!file.getOwner().equals(destination.getOwner())) {
1185 // (a) check if the destination quota allows the move
1186 if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1187 throw new QuotaExceededException("Not enough free space available");
1188 User newOwner = destination.getOwner();
1189 // (b) if quota OK, change the owner of the file
1190 file.setOwner(newOwner);
1191 // if the file has no permission for the new owner, add it
1192 Permission ownerPermission = null;
1193 for (final Permission p : file.getPermissions())
1194 if (p.getUser() != null)
1195 if (p.getUser().equals(newOwner)) {
1196 ownerPermission = p;
1199 if (ownerPermission == null) {
1200 ownerPermission = new Permission();
1201 ownerPermission.setUser(newOwner);
1202 file.addPermission(ownerPermission);
1204 ownerPermission.setRead(true);
1205 ownerPermission.setWrite(true);
1206 ownerPermission.setModifyACL(true);
1208 // move the file to the destination folder
1209 file.setFolder(destination);
1210 touchParentFolders(source, owner, new Date());
1211 touchParentFolders(destination, owner, new Date());
1215 public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1217 throw new ObjectNotFoundException("No user specified");
1218 if (ownerId == null)
1219 throw new ObjectNotFoundException("No owner specified");
1220 if (folderId == null)
1221 throw new ObjectNotFoundException("No folder specified");
1222 if (StringUtils.isEmpty(dest))
1223 throw new ObjectNotFoundException("No destination specified");
1225 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1226 if (!(destination instanceof FolderDTO))
1227 throw new ObjectNotFoundException("Destination parent folder not found");
1228 FolderDTO parent = (FolderDTO) destination;
1229 moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1233 public void moveFolder(Long userId, Long folderId, Long destId, String destName)
1234 throws ObjectNotFoundException, InsufficientPermissionsException,
1235 QuotaExceededException {
1236 Folder source = dao.getEntityById(Folder.class, folderId);
1237 Folder destination = dao.getEntityById(Folder.class, destId);
1238 User user = dao.getEntityById(User.class, userId);
1239 User sourceOwner = source.getOwner();
1240 User destinationOwner = destination.getOwner();
1241 // Do not move trashed folders and contents.
1242 if (source.isDeleted())
1244 // Check permissions.
1245 if (!destination.hasWritePermission(user)
1246 || !source.hasReadPermission(user)
1247 || !source.hasWritePermission(user))
1248 throw new InsufficientPermissionsException("You don't have the " +
1249 "necessary permissions");
1250 // Use the same timestamp for all subsequent modifications to make
1251 // changes appear simultaneous.
1252 Date now = new Date();
1253 // If source and destination are not in the same user's namespace,
1254 // change owners and check quota.
1255 if (!sourceOwner.equals(destinationOwner)) {
1256 changeOwner(source, destinationOwner, user, now);
1257 if (getQuotaLeft(destinationOwner.getId()) < 0)
1258 throw new QuotaExceededException("Not enough free space " +
1259 "available in destination folder");
1261 // Perform the move.
1262 Folder oldParent = source.getParent();
1263 oldParent.removeSubfolder(source);
1264 destination.addSubfolder(source);
1265 // Mark the former parent and destination trees upwards as modified.
1266 touchParentFolders(oldParent, user, now);
1267 touchParentFolders(source, user, now);
1271 * Recursively change the owner of the specified folder and all of its
1272 * contents to the specified owner. Also mark them all as modified with the
1273 * specified modifier and modificationDate.
1275 private void changeOwner(Folder folder, User owner, User modifier, Date modificationDate) {
1276 for (FileHeader file: folder.getFiles()) {
1277 file.setOwner(owner);
1278 file.getAuditInfo().setModificationDate(modificationDate);
1279 file.getAuditInfo().setModifiedBy(modifier);
1281 for (Folder sub: folder.getSubfolders())
1282 changeOwner(sub, owner, modifier, modificationDate);
1283 folder.setOwner(owner);
1284 folder.getAuditInfo().setModificationDate(modificationDate);
1285 folder.getAuditInfo().setModifiedBy(modifier);
1289 public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1292 throw new ObjectNotFoundException("No user specified");
1294 // Do the actual work.
1295 final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1296 final List<FileHeader> files = dao.getDeletedFiles(userId);
1297 for (final FileHeader f : files)
1298 result.add(f.getDTO());
1303 public void removeFileFromTrash(Long userId, Long fileId)
1304 throws ObjectNotFoundException, InsufficientPermissionsException {
1306 throw new ObjectNotFoundException("No user specified");
1308 throw new ObjectNotFoundException("No file specified");
1310 // Do the actual work.
1311 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1312 Folder parent = file.getFolder();
1314 throw new ObjectNotFoundException("The specified file has no parent folder");
1315 User user = dao.getEntityById(User.class, userId);
1316 if (!file.hasDeletePermission(user))
1317 throw new InsufficientPermissionsException("User " + user.getUsername() +
1318 " cannot restore file " + file.getName());
1320 file.setDeleted(false);
1322 touchParentFolders(parent, user, new Date());
1326 public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1328 throw new ObjectNotFoundException("No user specified");
1329 if (folderId == null)
1330 throw new ObjectNotFoundException("No folder specified");
1331 Folder folder = dao.getEntityById(Folder.class, folderId);
1332 User user = dao.getEntityById(User.class, userId);
1333 if (!folder.hasDeletePermission(user))
1334 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1335 folder.setDeleted(true);
1337 touchParentFolders(folder, user, new Date());
1338 for (FileHeader file : folder.getFiles())
1339 moveFileToTrash(userId, file.getId());
1340 for (Folder subFolder : folder.getSubfolders())
1341 moveFolderToTrash(userId, subFolder.getId());
1346 public void removeFolderFromTrash(Long userId, Long folderId)
1347 throws ObjectNotFoundException, InsufficientPermissionsException {
1349 throw new ObjectNotFoundException("No user specified");
1350 if (folderId == null)
1351 throw new ObjectNotFoundException("No folder specified");
1352 Folder folder = dao.getEntityById(Folder.class, folderId);
1353 User user = dao.getEntityById(User.class, userId);
1354 if (!folder.hasDeletePermission(user))
1355 throw new InsufficientPermissionsException("User " + user.getUsername() +
1356 " cannot restore folder " + folder.getName());
1357 folder.setDeleted(false);
1358 for (FileHeader file : folder.getFiles())
1359 removeFileFromTrash(userId, file.getId());
1360 for (Folder subFolder : folder.getSubfolders())
1361 removeFolderFromTrash(userId, subFolder.getId());
1363 touchParentFolders(folder, user, new Date());
1367 public List<FolderDTO> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1368 List<Folder> folders = dao.getDeletedRootFolders(userId);
1369 List<FolderDTO> result = new ArrayList<FolderDTO>();
1370 for (Folder folder : folders)
1371 result.add(folder.getDTO());
1376 public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1377 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1378 for (FolderDTO fdto : deletedRootFolders)
1379 deleteFolder(userId, fdto.getId());
1380 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1381 for (FileHeaderDTO filedto : deletedFiles)
1382 deleteFile(userId, filedto.getId());
1386 public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1387 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1388 for (FolderDTO fdto : deletedRootFolders)
1389 removeFolderFromTrash(userId, fdto.getId());
1390 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1391 for (FileHeaderDTO filedto : deletedFiles)
1392 removeFileFromTrash(userId, filedto.getId());
1396 public User createUser(String username, String name, String mail,
1397 String idp, String idpid) throws ObjectNotFoundException {
1398 if (username == null)
1399 throw new ObjectNotFoundException("No username specified");
1401 throw new ObjectNotFoundException("No name specified");
1403 User user = new User();
1404 user.setUsername(username);
1406 user.setEmail(mail);
1407 user.setIdentityProvider(idp);
1408 user.setIdentityProviderId(idpid);
1409 Date now = new Date();
1410 AuditInfo auditInfo = new AuditInfo();
1411 auditInfo.setCreationDate(now);
1412 auditInfo.setModificationDate(now);
1413 user.setAuditInfo(auditInfo);
1414 user.setActive(true);
1415 user.generateAuthToken();
1416 user.generateWebDAVPassword();
1417 user.setUserClass(getDefaultUserClass());
1419 // Make sure we get an ID in the user object.
1421 // Create the root folder for the user.
1422 createFolder(user.getName(), null, user);
1427 * Get the default user class, which is the one with the lowest quota.
1429 private UserClass getDefaultUserClass() {
1430 return getUserClasses().get(0);
1434 public List<UserClass> getUserClasses() {
1435 List<UserClass> classes = dao.getUserClasses();
1436 // Create a default user class for first-time use. Afterwards, the
1437 // admin should modify or add to the userclass table.
1438 if (classes.size() == 0) {
1439 UserClass defaultClass = new UserClass();
1440 defaultClass.setName("default");
1441 Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L));
1442 defaultClass.setQuota(defaultQuota);
1443 dao.create(defaultClass);
1444 classes.add(defaultClass);
1450 public User findUserByEmail(String email) {
1451 return dao.findUserByEmail(email);
1455 public void updateUser(User user) {
1460 public User findUser(String username) {
1461 if (username == null)
1463 return dao.findUser(username);
1467 public User updateUserToken(Long userId) throws ObjectNotFoundException {
1469 throw new ObjectNotFoundException("No user specified");
1470 User user = dao.getEntityById(User.class, userId);
1471 user.generateAuthToken();
1476 public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1478 throw new ObjectNotFoundException("No user specified");
1479 if (folderId == null)
1480 throw new ObjectNotFoundException("No folder specified");
1481 User user = dao.getEntityById(User.class, userId);
1482 Folder folder = dao.getEntityById(Folder.class, folderId);
1483 if(!folder.hasReadPermission(user))
1484 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1485 Set<Permission> perms = folder.getPermissions();
1486 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1487 for (Permission perm : perms)
1488 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1489 result.add(perm.getDTO());
1490 for (Permission perm : perms)
1491 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1493 result.add(perm.getDTO());
1499 * Set the provided permissions as the new permissions of the specified
1504 * @param permissions
1505 * @throws ObjectNotFoundException
1506 * @throws InsufficientPermissionsException
1508 private void setFolderPermissions(User user, Folder folder, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1509 if (permissions != null && !permissions.isEmpty()) {
1510 User owner = folder.getOwner();
1511 PermissionDTO ownerPerm = null;
1512 for (PermissionDTO dto : permissions)
1513 if (dto.getUser() != null && dto.getUser().getId().equals(owner.getId())) {
1517 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1518 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1519 // Delete previous entries
1520 for (Permission perm: folder.getPermissions())
1522 folder.getPermissions().clear();
1523 for (PermissionDTO dto : permissions) {
1524 // Skip 'empty' permission entries.
1525 if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1526 folder.addPermission(getPermission(dto));
1529 for (FileHeader file : folder.getFiles()) {
1530 setFilePermissions(file, permissions);
1531 Date now = new Date();
1532 file.getAuditInfo().setModificationDate(now);
1533 file.getAuditInfo().setModifiedBy(user);
1535 for (Folder sub : folder.getSubfolders())
1536 setFolderPermissions(user, sub, permissions);
1540 private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1541 Permission res = new Permission();
1542 if (dto.getGroup() != null)
1543 res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1544 else if (dto.getUser() != null)
1545 if (dto.getUser().getId() == null)
1546 res.setUser(dao.getUser(dto.getUser().getUsername()));
1548 res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1549 res.setRead(dto.hasRead());
1550 res.setWrite(dto.hasWrite());
1551 res.setModifyACL(dto.hasModifyACL());
1556 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1559 public List<UserDTO> getUsersByUserNameLike(String username) {
1560 List<User> users = dao.getUsersByUserNameLike(username);
1561 List<UserDTO> result = new ArrayList<UserDTO>();
1562 for (User u : users)
1563 result.add(u.getDTO());
1569 public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1571 throw new ObjectNotFoundException("No user specified");
1572 if (groupId == null)
1573 throw new ObjectNotFoundException("No group specified");
1574 if (userToAddId == null)
1575 throw new ObjectNotFoundException("No user to add specified");
1576 User user = dao.getEntityById(User.class, userId);
1577 Group group = dao.getEntityById(Group.class, groupId);
1578 if (!group.getOwner().equals(user))
1579 throw new InsufficientPermissionsException();
1580 User userToAdd = dao.getEntityById(User.class, userToAddId);
1581 if (group.contains(userToAdd))
1582 throw new DuplicateNameException("User already exists in group");
1583 group.getMembers().add(userToAdd);
1589 public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1591 throw new ObjectNotFoundException("No user specified");
1592 User user = dao.getEntityById(User.class, userId);
1593 user.invalidateAuthToken();
1598 public List<FolderDTO> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1600 throw new ObjectNotFoundException("No user specified");
1601 List<Folder> folders = dao.getSharedRootFolders(userId);
1602 List<FolderDTO> result = new ArrayList<FolderDTO>();
1603 for (Folder f : folders) {
1604 FolderDTO dto = f.getDTO();
1605 dto.setSubfolders(getSharedSubfolders(userId, f.getId()));
1612 public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1614 throw new ObjectNotFoundException("No user specified");
1615 if (groupId == null)
1616 throw new ObjectNotFoundException("No group specified");
1617 if (memberId == null)
1618 throw new ObjectNotFoundException("No member specified");
1619 User owner = dao.getEntityById(User.class, userId);
1620 Group group = dao.getEntityById(Group.class, groupId);
1621 User member = dao.getEntityById(User.class, memberId);
1622 if (!group.getOwner().equals(owner))
1623 throw new InsufficientPermissionsException("User is not the owner of the group");
1624 group.removeMemberFromGroup(member);
1630 public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1631 List<User> users = dao.getUsersSharingFoldersForUser(userId);
1632 List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1633 List<UserDTO> res = new ArrayList<UserDTO>();
1634 for (User u : users)
1635 res.add(u.getDTO());
1636 for(User fu : usersFiles)
1637 if(!users.contains(fu))
1638 res.add(fu.getDTO());
1643 public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1645 throw new ObjectNotFoundException("No user specified");
1647 throw new ObjectNotFoundException("No folder specified");
1648 User user = dao.getEntityById(User.class, userId);
1649 FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1650 if(!folder.hasReadPermission(user))
1651 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1652 Set<Permission> perms = folder.getPermissions();
1653 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1654 for (Permission perm : perms)
1655 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1656 result.add(perm.getDTO());
1657 for (Permission perm : perms)
1658 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1660 result.add(perm.getDTO());
1665 * Set the provided permissions as the new permissions of the specified
1666 * file. This method sets the modification date/user attributes to the
1667 * current values as a side effect.
1670 * @param permissions
1671 * @throws ObjectNotFoundException
1672 * @throws InsufficientPermissionsException
1674 private void setFilePermissions(FileHeader file,
1675 Set<PermissionDTO> permissions)
1676 throws ObjectNotFoundException, InsufficientPermissionsException {
1677 if (permissions != null && !permissions.isEmpty()) {
1678 PermissionDTO ownerPerm = null;
1679 for (PermissionDTO dto : permissions)
1680 if (dto.getUser() != null && dto.getUser().getId().equals(file.getOwner().getId())) {
1684 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1685 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1686 // Delete previous entries.
1687 for (Permission perm: file.getPermissions())
1689 file.getPermissions().clear();
1690 for (PermissionDTO dto : permissions) {
1691 // Skip 'empty' permission entries.
1692 if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1693 file.addPermission(getPermission(dto));
1700 public List<FileHeaderDTO> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1702 throw new ObjectNotFoundException("No user specified");
1703 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1704 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1705 for (FileHeader f : files)
1706 result.add(f.getDTO());
1711 public List<FileHeaderDTO> getSharedFiles(Long userId) throws ObjectNotFoundException {
1713 throw new ObjectNotFoundException("No user specified");
1714 List<FileHeader> files = dao.getSharedFiles(userId);
1715 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1716 for (FileHeader f : files)
1717 result.add(f.getDTO());
1722 public List<FolderDTO> getSharedFolders(Long userId) throws ObjectNotFoundException {
1724 throw new ObjectNotFoundException("No user specified");
1725 List<Folder> folders = dao.getSharedFolders(userId);
1726 List<FolderDTO> result = new ArrayList<FolderDTO>();
1727 for (Folder f : folders)
1728 result.add(f.getDTO());
1733 public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1734 if (ownerId == null)
1735 throw new ObjectNotFoundException("No owner specified");
1736 if (callingUserId == null)
1737 throw new ObjectNotFoundException("No calling user specified");
1738 List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1739 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1740 for (FileHeader f : folders)
1741 result.add(f.getDTO());
1746 public List<FolderDTO> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1747 if (ownerId == null)
1748 throw new ObjectNotFoundException("No owner specified");
1749 if (callingUserId == null)
1750 throw new ObjectNotFoundException("No calling user specified");
1751 List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1752 List<FolderDTO> result = new ArrayList<FolderDTO>();
1753 for (Folder f : folders) {
1754 FolderDTO dto = f.getDTO();
1755 dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1763 public List<FolderDTO> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1765 throw new ObjectNotFoundException("No user specified");
1766 if (folderId == null)
1767 throw new ObjectNotFoundException("No folder specified");
1768 User user = dao.getEntityById(User.class, userId);
1769 Folder folder = dao.getEntityById(Folder.class, folderId);
1770 List<FolderDTO> result = new ArrayList<FolderDTO>();
1771 if (folder.isShared(user) || folder.isReadForAll())
1772 for (Folder f : folder.getSubfolders())
1773 if ((f.isShared(user) || f.isReadForAll()) && !f.isDeleted())
1774 result.add(f.getDTO());
1779 public List<FolderDTO> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1781 throw new ObjectNotFoundException("No user specified");
1782 if (callingUserId == null)
1783 throw new ObjectNotFoundException("No user specified");
1784 if (folderId == null)
1785 throw new ObjectNotFoundException("No folder specified");
1786 User user = dao.getEntityById(User.class, callingUserId);
1787 Folder folder = dao.getEntityById(Folder.class, folderId);
1788 List<FolderDTO> result = new ArrayList<FolderDTO>();
1789 if (folder.isSharedForOtherUser(user))
1790 for (Folder f : folder.getSubfolders())
1791 if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1792 FolderDTO dto = f.getDTO();
1793 dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId()));
1801 public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1803 throw new ObjectNotFoundException("No user specified");
1804 User user = getUser(userId);
1806 throw new ObjectNotFoundException("No query specified");
1807 List<FileHeader> files = search(user.getId(), query);
1808 List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1809 for(FileHeader f : files)
1810 res.add(f.getDTO());
1815 * Performs the actuals search on the solr server and returns the results
1817 * We have to use the dismax query type (instead of the
1818 * standard) because it allows for search time field boosting. This is because we can't use indexing
1819 * time field boosting due to the patched rich indexing API that does not allow it
1823 * @return a List of FileHeader objects
1825 private List<FileHeader> search(Long userId, String query) {
1827 HttpClient httpClient = new HttpClient();
1829 GetMethod method = new GetMethod(getConfiguration().getString("solrSelectUrl"));
1830 NameValuePair[] params = {new NameValuePair("qt", "dismax"),
1831 new NameValuePair("q", query),
1832 new NameValuePair("sort", "score desc"),
1833 new NameValuePair("indent", "on")};
1834 method.setQueryString(params);
1837 String response = null;
1839 statusCode = httpClient.executeMethod(method);
1840 logger.debug("HTTP status: " + statusCode);
1841 response = method.getResponseBodyAsString();
1842 logger.debug(response);
1844 if (statusCode != 200 && retryCount < 3)
1846 Thread.sleep(3000); //Give Solr a little time to be available
1847 } catch (InterruptedException e) {
1849 } while (statusCode != 200 && retryCount < 3);
1850 if (statusCode != 200)
1851 throw new EJBException("Search query return error:\n" + response);
1853 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1854 DocumentBuilder db = dbf.newDocumentBuilder();
1855 Document doc = db.parse(method.getResponseBodyAsStream());
1856 method.releaseConnection();
1858 Node root = doc.getElementsByTagName("response").item(0);
1859 Node lst = root.getFirstChild().getNextSibling();
1860 Node status = lst.getFirstChild().getNextSibling();
1861 if (status.getAttributes().getNamedItem("name").getNodeValue().equals("status") &&
1862 status.getTextContent().equals("0")) {
1863 List<FileHeader> fileResult = new ArrayList<FileHeader>();
1864 Node result = lst.getNextSibling().getNextSibling();
1865 NodeList docs = result.getChildNodes();
1866 User user = getUser(userId);
1867 for (int i=1; i<docs.getLength(); i=i+2) {
1868 Node d = docs.item(i);
1869 NodeList docData = d.getChildNodes();
1870 for (int j=1; j<docData.getLength(); j=j+2) {
1871 Node dd = docData.item(j);
1872 if (dd.getAttributes().item(0).getNodeName().equals("name") &&
1873 dd.getAttributes().item(0).getNodeValue().equals("id")) {
1874 Long fileId = Long.valueOf(dd.getTextContent());
1876 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1877 if (file.hasReadPermission(user)) {
1878 fileResult.add(file);
1879 logger.debug("File added " + fileId);
1881 } catch (ObjectNotFoundException e) {
1882 logger.warn("Search result not found", e);
1889 throw new EJBException();
1890 } catch (HttpException e) {
1891 throw new EJBException(e);
1892 } catch (IOException e) {
1893 throw new EJBException(e);
1894 } catch (SAXException e) {
1895 throw new EJBException(e);
1896 } catch (ParserConfigurationException e) {
1897 throw new EJBException(e);
1898 } catch (ObjectNotFoundException e) {
1899 throw new EJBException(e);
1904 public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1905 for(Long l : fileIds){
1906 FileHeader file = dao.getEntityById(FileHeader.class, l);
1907 copyFile(userId, l, destId, file.getName());
1914 public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1915 for(Long l : fileIds){
1916 FileHeader file = dao.getEntityById(FileHeader.class, l);
1917 moveFile(userId, l, destId, file.getName());
1923 public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1925 throw new ObjectNotFoundException("No user specified");
1926 final User user = dao.getEntityById(User.class, userId);
1927 List<String> filesToRemove = new ArrayList<String>();
1928 //first delete database objects
1929 for(Long fileId : fileIds){
1931 throw new ObjectNotFoundException("No file specified");
1932 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1933 final Folder parent = file.getFolder();
1935 throw new ObjectNotFoundException("The specified file has no parent folder");
1936 if (!file.hasDeletePermission(user))
1937 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1939 parent.removeFile(file);
1940 for (final FileBody body : file.getBodies())
1941 filesToRemove.add(body.getStoredFilePath());
1943 touchParentFolders(parent, user, new Date());
1945 //then remove physical files if everything is ok
1946 for(String physicalFileName : filesToRemove)
1947 deleteActualFile(physicalFileName);
1948 //then unindex deleted files
1949 for(Long fileId : fileIds)
1950 indexFile(fileId, true);
1955 public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1956 for(Long l : fileIds)
1957 moveFileToTrash(userId, l);
1962 public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1963 for(Long l : fileIds)
1964 removeFileFromTrash(userId, l);
1969 public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1971 throw new ObjectNotFoundException("No user specified");
1972 User user = dao.getEntityById(User.class, userId);
1973 Nonce nonce = Nonce.createNonce(user.getId());
1979 public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1981 throw new ObjectNotFoundException("No user specified");
1983 throw new ObjectNotFoundException("No nonce specified");
1984 return dao.getNonce(nonce, userId);
1988 public void removeNonce(Long id) throws ObjectNotFoundException {
1990 throw new ObjectNotFoundException("No nonce specified");
1991 Nonce nonce = dao.getEntityById(Nonce.class, id);
1996 public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1998 throw new ObjectNotFoundException("No user specified");
1999 User user = dao.getEntityById(User.class, userId);
2000 user.setNonce(nonce);
2001 user.setNonceExpiryDate(nonceExpiryDate);
2005 public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
2007 throw new ObjectNotFoundException("No user specified");
2008 StatsDTO stats = new StatsDTO();
2009 stats.setFileCount(dao.getFileCount(userId));
2010 Long fileSize = dao.getFileSize(userId);
2011 stats.setFileSize(fileSize);
2012 Long quota = getQuota(userId);
2013 Long quotaLeft = quota - fileSize;
2014 stats.setQuotaLeftSize(quotaLeft);
2019 public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2021 throw new ObjectNotFoundException("No user specified");
2023 throw new ObjectNotFoundException("No file specified");
2024 User user = dao.getEntityById(User.class, userId);
2025 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2026 if(!header.hasReadPermission(user))
2027 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2028 List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
2029 for(int i = header.getBodies().size()-1 ; i>=0; i--)
2030 result.add(header.getBodies().get(i).getDTO());
2035 public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
2037 throw new ObjectNotFoundException("No user specified");
2039 throw new ObjectNotFoundException("No file specified");
2041 throw new ObjectNotFoundException("No body specified");
2042 User user = dao.getEntityById(User.class, userId);
2043 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2044 if(!header.hasWritePermission(user))
2045 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2046 FileBody body = dao.getEntityById(FileBody.class, bodyId);
2047 if(body.equals(header.getCurrentBody())){
2049 if(header.getBodies().size() == 1)
2050 throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
2051 for(FileBody b : header.getBodies())
2052 if(b.getVersion() == body.getVersion()-1)
2053 header.setCurrentBody(b);
2055 deleteActualFile(body.getStoredFilePath());
2056 header.getBodies().remove(body);
2058 Folder parent = header.getFolder();
2059 touchParentFolders(parent, user, new Date());
2064 public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
2066 throw new ObjectNotFoundException("No user specified");
2068 throw new ObjectNotFoundException("No file specified");
2069 User user = dao.getEntityById(User.class, userId);
2070 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2071 if(!header.hasWritePermission(user))
2072 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2073 FileBody body = dao.getFileVersion(fileId, version);
2074 final File fileContents = new File(body.getStoredFilePath());
2077 updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
2078 } catch (FileNotFoundException e) {
2079 throw new GSSIOException(e);
2085 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2088 public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2090 throw new ObjectNotFoundException("No user specified");
2092 throw new ObjectNotFoundException("No file specified");
2093 User user = dao.getEntityById(User.class, userId);
2094 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2095 if(!header.hasWritePermission(user))
2096 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2097 Iterator<FileBody> it = header.getBodies().iterator();
2098 while(it.hasNext()){
2099 FileBody body = it.next();
2100 if(!body.equals(header.getCurrentBody())){
2101 deleteActualFile(body.getStoredFilePath());
2106 header.getCurrentBody().setVersion(1);
2108 Folder parent = header.getFolder();
2109 touchParentFolders(parent, user, new Date());
2113 * Gets the quota left for specified user ID.
2115 private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
2116 Long fileSize = dao.getFileSize(userId);
2117 Long quota = getQuota(userId);
2118 return quota - fileSize;
2122 * Gets the quota for specified user ID.
2124 private Long getQuota(Long userId) throws ObjectNotFoundException{
2125 UserClass uc = getUser(userId).getUserClass();
2127 uc = getDefaultUserClass();
2128 return uc.getQuota();
2132 public void rebuildSolrIndex() {
2133 MessageProducer sender = null;
2134 Session session = null;
2135 Connection qConn = null;
2137 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2138 DocumentBuilder db = dbf.newDocumentBuilder();
2139 Document doc = db.newDocument();
2140 Node root = doc.createElement("delete");
2141 doc.appendChild(root);
2142 Node queryNode = doc.createElement("query");
2143 root.appendChild(queryNode);
2144 queryNode.appendChild(doc.createTextNode("*:*"));
2146 TransformerFactory fact = TransformerFactory.newInstance();
2147 Transformer trans = fact.newTransformer();
2148 trans.setOutputProperty(OutputKeys.INDENT, "yes");
2149 StringWriter sw = new StringWriter();
2150 StreamResult sr = new StreamResult(sw);
2151 DOMSource source = new DOMSource(doc);
2152 trans.transform(source, sr);
2153 logger.debug(sw.toString());
2155 HttpClient httpClient = new HttpClient();
2156 PostMethod method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2157 method.setRequestEntity(new StringRequestEntity(sw.toString()));
2160 String response = null;
2162 statusCode = httpClient.executeMethod(method);
2163 logger.debug("HTTP status: " + statusCode);
2164 response = method.getResponseBodyAsString();
2165 logger.debug(response);
2167 if (statusCode != 200 && retryCount < 3)
2169 Thread.sleep(10000); //Give Solr a little time to be available
2170 } catch (InterruptedException e) {
2172 } while (statusCode != 200 && retryCount < 3);
2173 method.releaseConnection();
2174 if (statusCode != 200)
2175 throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response);
2176 List<Long> fileIds = dao.getAllFileIds();
2178 Context jndiCtx = new InitialContext();
2179 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
2180 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
2181 qConn = factory.createConnection();
2182 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
2183 sender = session.createProducer(queue);
2185 for (Long id : fileIds) {
2186 MapMessage map = session.createMapMessage();
2187 map.setObject("id", id);
2188 map.setBoolean("delete", false);
2191 sendOptimize(httpClient, 0);
2192 } catch (DOMException e) {
2193 throw new EJBException(e);
2194 } catch (TransformerConfigurationException e) {
2195 throw new EJBException(e);
2196 } catch (IllegalArgumentException e) {
2197 throw new EJBException(e);
2198 } catch (HttpException e) {
2199 throw new EJBException(e);
2200 } catch (UnsupportedEncodingException e) {
2201 throw new EJBException(e);
2202 } catch (ParserConfigurationException e) {
2203 throw new EJBException(e);
2204 } catch (TransformerException e) {
2205 throw new EJBException(e);
2206 } catch (IOException e) {
2207 throw new EJBException(e);
2208 } catch (NamingException e) {
2209 throw new EJBException(e);
2210 } catch (JMSException e) {
2211 throw new EJBException(e);
2217 if (session != null)
2222 catch (JMSException e) {
2229 * Sends a optimize message to the solr server
2232 * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive
2233 * calls to stop the recursion
2234 * @throws UnsupportedEncodingException
2235 * @throws IOException
2236 * @throws HttpException
2238 private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException {
2239 PostMethod method = null;
2241 logger.debug("Optimize retry: " + retryCount);
2242 method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2243 method.setRequestEntity(new StringRequestEntity("<optimize/>", "text/xml", "iso8859-1"));
2244 int statusCode = httpClient.executeMethod(method);
2245 logger.debug("HTTP status: " + statusCode);
2246 String response = method.getResponseBodyAsString();
2247 logger.debug(response);
2248 if (statusCode != 200 && retryCount < 2) {
2250 Thread.sleep(10000); //Give Solr a little time to be available
2251 } catch (InterruptedException e) {
2253 sendOptimize(httpClient, retryCount + 1);
2258 method.releaseConnection();
2263 public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2264 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2265 InsufficientPermissionsException, QuotaExceededException {
2268 throw new ObjectNotFoundException("No user specified");
2269 if (folderId == null)
2270 throw new ObjectNotFoundException("No folder specified");
2271 String contentType = mimeType;
2272 if (StringUtils.isEmpty(mimeType))
2273 contentType = DEFAULT_MIME_TYPE;
2274 if (StringUtils.isEmpty(name))
2275 throw new ObjectNotFoundException("No file name specified");
2276 if (dao.existsFolderOrFile(folderId, name))
2277 throw new DuplicateNameException("A folder or file with the name '" + name +
2278 "' already exists at this level");
2280 // Do the actual work.
2281 Folder parent = null;
2283 parent = dao.getEntityById(Folder.class, folderId);
2284 } catch (final ObjectNotFoundException onfe) {
2285 // Supply a more accurate problem description.
2286 throw new ObjectNotFoundException("Parent folder not found");
2288 final User owner = dao.getEntityById(User.class, userId);
2289 if (!parent.hasWritePermission(owner))
2290 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2291 final FileHeader file = new FileHeader();
2293 parent.addFile(file);
2294 // set file owner to folder owner
2295 file.setOwner(parent.getOwner());
2296 //set file's readForAll value according to parent folder readForAll value
2297 file.setReadForAll(parent.isReadForAll());
2299 final Date now = new Date();
2300 final AuditInfo auditInfo = new AuditInfo();
2301 auditInfo.setCreatedBy(owner);
2302 auditInfo.setCreationDate(now);
2303 auditInfo.setModifiedBy(owner);
2304 auditInfo.setModificationDate(now);
2305 file.setAuditInfo(auditInfo);
2306 // TODO set the proper versioning flag on creation
2307 file.setVersioned(false);
2309 for (final Permission p : parent.getPermissions()) {
2310 final Permission permission = new Permission();
2311 permission.setGroup(p.getGroup());
2312 permission.setUser(p.getUser());
2313 permission.setRead(p.getRead());
2314 permission.setWrite(p.getWrite());
2315 permission.setModifyACL(p.getModifyACL());
2316 file.addPermission(permission);
2319 // Create the file body.
2321 createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2322 } catch (FileNotFoundException e) {
2323 throw new GSSIOException(e);
2325 touchParentFolders(parent, owner, new Date());
2327 indexFile(file.getId(), false);
2329 return file.getDTO();
2333 public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2335 throw new ObjectNotFoundException("No user specified");
2337 throw new ObjectNotFoundException("No file specified");
2338 String contentType = mimeType;
2340 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2342 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2343 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2344 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2345 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2346 contentType = identifyMimeType(file.getName());
2348 final User owner = dao.getEntityById(User.class, userId);
2349 if (!file.hasWritePermission(owner))
2350 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2351 final Date now = new Date();
2352 final AuditInfo auditInfo = new AuditInfo();
2353 auditInfo.setCreatedBy(owner);
2354 auditInfo.setCreationDate(now);
2355 auditInfo.setModifiedBy(owner);
2356 auditInfo.setModificationDate(now);
2358 createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2359 } catch (FileNotFoundException e) {
2360 throw new GSSIOException(e);
2362 Folder parent = file.getFolder();
2363 touchParentFolders(parent, owner, new Date());
2365 indexFile(fileId, false);
2366 return file.getDTO();
2370 * Helper method for identifying mime type by examining the filename extension
2373 * @return the mime type
2375 private String identifyMimeType(String filename) {
2376 if (filename.indexOf('.') != -1) {
2377 String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2378 if (".doc".equals(extension))
2379 return "application/msword";
2380 else if (".xls".equals(extension))
2381 return "application/vnd.ms-excel";
2382 else if (".ppt".equals(extension))
2383 return "application/vnd.ms-powerpoint";
2384 else if (".pdf".equals(extension))
2385 return "application/pdf";
2386 else if (".gif".equals(extension))
2388 else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2389 return "image/jpeg";
2390 else if (".tiff".equals(extension) || ".tif".equals(extension))
2391 return "image/tiff";
2392 else if (".png".equals(extension))
2394 else if (".bmp".equals(extension))
2397 // when all else fails assign the default mime type
2398 return DEFAULT_MIME_TYPE;
2402 * Helper method to create a new file body and attach it as the current body
2403 * of the provided file header.
2405 * @param name the original file name
2406 * @param mimeType the content type
2407 * @param fileSize the uploaded file size
2408 * @param filePath the uploaded file full path
2409 * @param header the file header that will be associated with the new body
2410 * @param auditInfo the audit info
2411 * @param owner the owner of the file
2412 * @throws FileNotFoundException
2413 * @throws QuotaExceededException
2414 * @throws ObjectNotFoundException if the owner was not found
2416 private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2417 FileHeader header, AuditInfo auditInfo)
2418 throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2420 long currentTotalSize = 0;
2421 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2422 currentTotalSize = header.getTotalSize();
2423 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2424 if(quotaLeft < fileSize-currentTotalSize) {
2425 // quota exceeded -> delete the file
2426 deleteActualFile(filePath);
2427 throw new QuotaExceededException("Not enough free space available");
2430 FileBody body = new FileBody();
2432 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2433 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2434 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2435 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2436 body.setMimeType(identifyMimeType(name));
2438 body.setMimeType(mimeType);
2439 body.setAuditInfo(auditInfo);
2440 body.setFileSize(fileSize);
2441 body.setOriginalFilename(name);
2442 body.setStoredFilePath(filePath);
2443 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2444 if(!header.isVersioned() && header.getCurrentBody() != null){
2445 header.setCurrentBody(null);
2446 if (header.getBodies() != null) {
2447 Iterator<FileBody> it = header.getBodies().iterator();
2448 while(it.hasNext()){
2449 FileBody bo = it.next();
2450 deleteActualFile(bo.getStoredFilePath());
2458 header.addBody(body);
2459 header.setAuditInfo(auditInfo);
2466 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2467 public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2469 throw new ObjectNotFoundException("No user specified");
2470 User owner = dao.getEntityById(User.class, userId);
2472 throw new ObjectNotFoundException("No user specified");
2473 long start = 0, end = 0;
2474 if (logger.isDebugEnabled())
2475 start = System.currentTimeMillis();
2476 File result = new File(generateRepositoryFilePath());
2478 final FileOutputStream output = new FileOutputStream(result);
2479 final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2482 while (-1 != (n = stream.read(buffer)))
2483 output.write(buffer, 0, n);
2486 } catch (IOException e) {
2487 if (!result.delete())
2488 logger.warn("Could not delete " + result.getPath());
2491 if (logger.isDebugEnabled()) {
2492 end = System.currentTimeMillis();
2493 logger.debug("Time to upload: " + (end - start) + " (msec)");
2500 public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2503 throw new ObjectNotFoundException("No user specified");
2504 User user = dao.getEntityById(User.class, userId);
2505 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2507 status = new FileUploadStatus();
2508 status.setOwner(user);
2509 status.setFilename(filename);
2510 status.setBytesUploaded(bytesTransfered);
2511 status.setFileSize(fileSize);
2515 status.setBytesUploaded(bytesTransfered);
2516 status.setFileSize(fileSize);
2523 public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2525 throw new ObjectNotFoundException("No user specified");
2526 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2532 public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2533 return dao.getFileUploadStatus(userId, fileName);
2537 public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2539 throw new ObjectNotFoundException("No user specified");
2540 if (folderId == null)
2541 throw new ObjectNotFoundException("No folder specified");
2542 final User user = dao.getEntityById(User.class, userId);
2543 final Folder folder = dao.getEntityById(Folder.class, folderId);
2544 // Check permissions
2545 if (!folder.hasReadPermission(user))
2546 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2547 List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2548 if (folder.hasReadPermission(user))
2549 for (Folder f : folder.getSubfolders())
2550 if (f.hasReadPermission(user) && !f.isDeleted())
2551 subfolders.add(f.getDTO());
2552 FolderDTO result = folder.getDTO();
2553 result.setSubfolders(subfolders);
2554 return folder.getDTO();
2558 public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2560 throw new ObjectNotFoundException("No user specified");
2561 if (folderId == null)
2562 throw new ObjectNotFoundException("No folder specified");
2563 User user = dao.getEntityById(User.class, callingUserId);
2564 Folder folder = dao.getEntityById(Folder.class, folderId);
2565 // Check permissions
2566 if (!folder.hasReadPermission(user))
2567 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2569 FolderDTO result = folder.getDTO();
2570 result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2575 public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2576 throws ObjectNotFoundException, InsufficientPermissionsException {
2578 throw new ObjectNotFoundException("No user specified");
2580 throw new ObjectNotFoundException("No file specified");
2582 throw new ObjectNotFoundException("No valid version specified");
2583 User user = dao.getEntityById(User.class, userId);
2584 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2585 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2586 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2587 FileBody body = dao.getFileVersion(fileId, version);
2588 return body.getDTO();
2592 public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2594 throw new ObjectNotFoundException("No user specified");
2595 User user = dao.getEntityById(User.class, userId);
2596 user.setAcceptedPolicy(isAccepted);
2601 public void updateAccounting(User user, Date date, long bandwidthDiff) {
2602 dao.updateAccounting(user, date, bandwidthDiff);
2606 public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2608 throw new ObjectNotFoundException("No user specified");
2609 if (folderId == null)
2610 throw new ObjectNotFoundException("No folder specified");
2611 User user = dao.getEntityById(User.class, userId);
2612 Folder folder = dao.getEntityById(Folder.class, folderId);
2613 // Check permissions
2614 if (!folder.hasReadPermission(user))
2620 public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2622 throw new ObjectNotFoundException("No user specified");
2623 User user = dao.getEntityById(User.class, userId);
2624 user.generateWebDAVPassword();
2625 return user.getWebDAVPassword();
2629 public Invitation findInvite(String code) {
2632 return dao.findInvite(code);
2636 public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2637 LDAPConnection lc = new LDAPConnection();
2638 LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2639 attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2640 attributeSet.add(new LDAPAttribute("uid", username));
2641 attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2642 attributeSet.add(new LDAPAttribute("sn", lastname));
2643 attributeSet.add(new LDAPAttribute("givenName", firstname));
2644 attributeSet.add(new LDAPAttribute("mail", email));
2645 attributeSet.add(new LDAPAttribute("userPassword", password));
2646 String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2647 LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2649 lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2650 lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2651 getConfiguration().getString("bindPassword").getBytes("UTF8"));
2653 logger.info("Successfully added LDAP account: " + dn);
2655 } catch(LDAPException e) {
2656 throw new RuntimeException(e);
2657 } catch(UnsupportedEncodingException e) {
2658 throw new RuntimeException(e);
2664 public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2665 User user = findUser(username);
2667 throw new ObjectNotFoundException("The user was not found");
2668 Invitation invite = findInvite(code);
2669 if (invite.getUser() != null)
2670 throw new InvitationUsedException("This code has already been used");
2671 invite.setUser(user);
2672 UserClass couponClass = getCouponUserClass();
2673 user.setUserClass(couponClass);
2678 public UserClass getCouponUserClass() {
2679 return dao.findCouponUserClass();
2683 * Mark the folder as modified from the specified user and change it's modification date.
2685 private void touchFolder(Folder f, User _user, Date now){
2686 final AuditInfo auditInfo = f.getAuditInfo();
2687 auditInfo.setModificationDate(now);
2688 auditInfo.setModifiedBy(_user);
2689 f.setAuditInfo(auditInfo);
2693 * Mark the file as modified from the specified user and change it's modification date.
2695 private void touchFile(FileHeader f, User _user, Date now){
2696 final AuditInfo auditInfo = f.getAuditInfo();
2697 auditInfo.setModificationDate(now);
2698 auditInfo.setModifiedBy(_user);
2699 f.setAuditInfo(auditInfo);
2703 * Set the provided readForAll as the new readforAll value of the specified
2704 * folder and sub-folders.
2709 * @throws ObjectNotFoundException
2712 private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){
2713 if (readForAll != null && user.equals(folder.getOwner())){
2714 folder.setReadForAll(readForAll);
2716 for (FileHeader file : folder.getFiles())
2717 file.setReadForAll(readForAll);
2719 //only update subfolders when readforall is true. otherwise all sub-folders stay untouched
2720 for (Folder sub : folder.getSubfolders())
2721 setFolderReadForAll(user, sub, readForAll);