2 * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
4 * This file is part of GSS.
6 * GSS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GSS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GSS. If not, see <http://www.gnu.org/licenses/>.
19 package gr.ebs.gss.server.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);
346 return folder.getDTO();
350 public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
353 throw new ObjectNotFoundException("No user specified");
354 if (folderId == null)
355 throw new ObjectNotFoundException("No folder specified");
357 // Do the actual work.
358 final Folder folder = dao.getEntityById(Folder.class, folderId);
359 final Folder parent = folder.getParent();
361 throw new ObjectNotFoundException("Deleting the root folder is not allowed");
362 final User user = dao.getEntityById(User.class, userId);
363 if (!folder.hasDeletePermission(user)) {
364 logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
365 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
367 removeSubfolderFiles(folder);
368 parent.removeSubfolder(folder);
370 touchParentFolders(parent, user, new Date());
374 * Traverses the folder and deletes all actual files (file system)
375 * regardless of permissions
379 private void removeSubfolderFiles(Folder folder) {
380 //remove files for all subfolders
381 for (Folder subfolder:folder.getSubfolders())
382 removeSubfolderFiles(subfolder);
383 //remove this folder's file bodies (actual files)
384 for (FileHeader file:folder.getFiles()) {
385 for (FileBody body:file.getBodies())
386 deleteActualFile(body.getStoredFilePath());
387 indexFile(file.getId(), true);
392 @SuppressWarnings("unchecked")
393 public List<FolderDTO> getSubfolders(Long userId, Long folderId)
394 throws ObjectNotFoundException, InsufficientPermissionsException {
396 throw new ObjectNotFoundException("No user specified");
397 if (folderId == null)
398 throw new ObjectNotFoundException("No folder specified");
399 User user = dao.getEntityById(User.class, userId);
400 Folder folder = dao.getEntityById(Folder.class, folderId);
401 if (!folder.hasReadPermission(user))
402 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
403 List<FolderDTO> result = new ArrayList<FolderDTO>();
404 if (folder.hasReadPermission(user))
405 for (Folder f : folder.getSubfolders())
406 if (f.hasReadPermission(user) && !f.isDeleted())
407 result.add(f.getDTO());
412 public FolderDTO updateFolder(Long userId, Long folderId, String folderName,
414 Set<PermissionDTO> permissions)
415 throws InsufficientPermissionsException, ObjectNotFoundException,
416 DuplicateNameException {
420 throw new ObjectNotFoundException("No user specified");
421 if (folderId == null)
422 throw new ObjectNotFoundException("No folder specified");
424 Folder folder = dao.getEntityById(Folder.class, folderId);
425 User user = dao.getEntityById(User.class, userId);
426 if (folderName != null && !folder.hasWritePermission(user))
427 throw new InsufficientPermissionsException("You don't have the necessary permissions");
428 if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
429 throw new InsufficientPermissionsException("You don't have the necessary permissions");
430 // Check permissions for making file public.
431 if (readForAll != null && !user.equals(folder.getOwner()))
432 throw new InsufficientPermissionsException("Only the owner can make a folder public or not public");
434 Folder parent = folder.getParent();
435 if (folderName != null) {
437 if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
438 throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
440 // Do the actual modification.
441 folder.setName(folderName);
443 if (permissions != null)
444 setFolderPermissions(user, folder, permissions);
445 if (readForAll != null && user.equals(folder.getOwner()))
446 folder.setReadForAll(readForAll);
448 folder.getAuditInfo().setModificationDate(new Date());
449 folder.getAuditInfo().setModifiedBy(user);
451 touchParentFolders(folder, user, new Date());
452 return folder.getDTO();
456 public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
459 throw new ObjectNotFoundException("No user specified");
460 if (StringUtils.isEmpty(name))
461 throw new ObjectNotFoundException("New group name is empty");
462 if (name.indexOf('/')>=0)
463 throw new IllegalArgumentException("Character '/' is not allowed in group name");
464 if (dao.existsGroup(userId, name))
465 throw new DuplicateNameException("A group with the name '" + name + "' already exists");
467 // TODO: Check permissions
469 final User owner = dao.getEntityById(User.class, userId);
471 // Do the actual work.
472 owner.createGroup(name);
476 public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
479 throw new ObjectNotFoundException("No user specified");
481 throw new ObjectNotFoundException("No group specified");
483 // Do the actual work.
484 final User owner = dao.getEntityById(User.class, userId);
485 final Group group = dao.getEntityById(Group.class, groupId);
486 // Only delete the group if actually owned by the user.
487 if (group.getOwner().equals(owner)) {
488 List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
489 for (Folder f : folders){
490 f.getPermissions().removeAll(group.getPermissions());
491 for(FileHeader file : f.getFiles())
492 file.getPermissions().removeAll(group.getPermissions());
494 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
495 for(FileHeader h : files)
496 h.getPermissions().removeAll(group.getPermissions());
497 owner.removeSpecifiedGroup(group);
500 else throw new InsufficientPermissionsException("You are not the owner of this group");
504 public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
505 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
506 InsufficientPermissionsException, QuotaExceededException {
509 file = uploadFile(stream, userId);
510 } catch ( IOException ioe) {
511 // Supply a more accurate problem description.
512 throw new GSSIOException("Problem creating file",ioe);
514 return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
518 * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
521 public void indexFile(Long fileId, boolean delete) {
522 Connection qConn = null;
523 Session session = null;
524 MessageProducer sender = null;
526 Context jndiCtx = new InitialContext();
527 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
528 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
529 qConn = factory.createConnection();
530 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
531 sender = session.createProducer(queue);
533 MapMessage map = session.createMapMessage();
534 map.setObject("id", fileId);
535 map.setBoolean("delete", delete);
538 catch (NamingException e) {
539 logger.error("Index was not updated: ", e);
541 catch (JMSException e) {
542 logger.error("Index was not updated: ", e);
553 catch (JMSException e) {
562 * A helper method that generates a unique file path for a stored file. The
563 * files are stored using random hash names that are distributed evenly in
564 * a 2-level tree of subdirectories named after the first two hex characters
565 * in the name. For example, file ab1234cd5769f will be stored in the path
566 * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
567 * if they don't already exist.
569 * @return a unique new file path
571 private String generateRepositoryFilePath() {
572 String filename = Long.toHexString(random.nextLong());
573 String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
574 File root = new File(fileRepositoryPath);
577 File firstFolder = new File(root + File.separator + filename.substring(0, 1));
578 if (!firstFolder.exists())
580 File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
581 if (!secondFolder.exists())
582 secondFolder.mkdir();
583 return secondFolder + File.separator + filename;
587 public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
590 throw new ObjectNotFoundException("No user specified");
592 throw new ObjectNotFoundException("No file specified");
594 // Do the actual work.
595 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
596 final Folder parent = file.getFolder();
598 throw new ObjectNotFoundException("The specified file has no parent folder");
599 final User user = dao.getEntityById(User.class, userId);
600 if (!file.hasDeletePermission(user))
601 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
602 for (final FileBody body : file.getBodies())
603 deleteActualFile(body.getStoredFilePath());
605 touchParentFolders(parent, user, new Date());
606 indexFile(fileId, true);
610 public void deleteActualFile(String path) {
613 File file = new File(path);
615 logger.error("Could not delete file " + path);
619 public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
621 throw new ObjectNotFoundException("No user specified");
622 if (fileHeaderId == null)
623 throw new ObjectNotFoundException("No file specified");
624 if (StringUtils.isEmpty(tag))
625 throw new ObjectNotFoundException("Tag is empty");
627 final User user = dao.getEntityById(User.class, userId);
628 final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
629 final Folder parent = fh.getFolder();
631 throw new ObjectNotFoundException("The specified file has no parent folder");
632 user.addTag(fh, tag);
633 touchParentFolders(parent, user, new Date());
637 public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
638 return dao.getUserTags(userId);
642 public void updateFile(Long userId, Long fileId, String name,
643 String tagSet, Date modificationDate, Boolean versioned,
644 Boolean readForAll, Set<PermissionDTO> permissions)
645 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
647 throw new ObjectNotFoundException("No user specified");
649 throw new ObjectNotFoundException("No file specified");
650 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
651 final Folder parent = file.getFolder();
653 throw new ObjectNotFoundException("The specified file has no parent folder");
655 User user = dao.getEntityById(User.class, userId);
656 // Check permissions for modifying the file metadata.
657 if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
658 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
659 // Check permissions for making file public.
660 if (readForAll != null && !user.equals(file.getOwner()))
661 throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
662 // Check permissions for modifying the ACL.
663 if(permissions != null && !permissions.isEmpty() && !file.hasModifyACLPermission(user))
664 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update the permissions on file " + file.getName() + "(" + file.getId() + ")");
667 // Do plain check for file already exists.
668 // Extreme concurrency case should be caught by constraint violation later.
669 if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
673 if (modificationDate != null)
674 file.getAuditInfo().setModificationDate(modificationDate);
676 file.getAuditInfo().setModificationDate(new Date());
677 file.getAuditInfo().setModifiedBy(user);
679 List<FileTag> tags = file.getFileTags();
680 if (tagSet != null) {
681 Iterator<FileTag> i = tags.iterator();
682 while (i.hasNext()) {
683 FileTag tag = i.next();
690 StringTokenizer st = new StringTokenizer(tagSet, ",");
691 while (st.hasMoreTokens())
692 new FileTag(user, file, st.nextToken().trim());
694 if (versioned != null && !file.isVersioned() == versioned) {
695 if (file.isVersioned())
696 removeOldVersions(userId, fileId);
697 file.setVersioned(versioned);
699 if (readForAll != null && user.equals(file.getOwner()))
700 file.setReadForAll(readForAll);
701 if (permissions != null && !permissions.isEmpty())
702 setFilePermissions(file, permissions);
705 * Force constraint violation to manifest itself here.
706 * This should cover extreme concurrency cases that the simple check
707 * above hasn't caught.
712 catch (EJBTransactionRolledbackException e) {
713 Throwable cause = e.getCause();
714 if (cause instanceof PersistenceException && cause.getCause() instanceof ConstraintViolationException)
715 throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
719 touchParentFolders(parent, user, new Date());
721 // Re-index the file if it was modified.
722 if (name != null || tagSet != null)
723 indexFile(fileId, false);
727 public InputStream getFileContents(Long userId, Long fileId)
728 throws ObjectNotFoundException, InsufficientPermissionsException {
730 throw new ObjectNotFoundException("No user specified");
732 throw new ObjectNotFoundException("No file specified");
734 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
735 User user = dao.getEntityById(User.class, userId);
736 if (!header.hasReadPermission(user)) {
737 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
738 throw new InsufficientPermissionsException("You don't have the necessary permissions");
741 File f = new File(header.getCurrentBody().getStoredFilePath());
743 return new FileInputStream(f);
744 } catch (FileNotFoundException e) {
745 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
746 throw new ObjectNotFoundException("The file contents could not be located");
751 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
754 public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
756 throw new ObjectNotFoundException("No user specified");
758 throw new ObjectNotFoundException("No file specified");
760 throw new ObjectNotFoundException("No file specified");
762 final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
763 final FileBody body = dao.getEntityById(FileBody.class, bodyId);
764 final User user = dao.getEntityById(User.class, userId);
765 if (!header.hasReadPermission(user)) {
766 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
767 throw new InsufficientPermissionsException("You don't have the necessary permissions");
770 File f = new File(body.getStoredFilePath());
772 return new FileInputStream(f);
773 } catch (FileNotFoundException e) {
774 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
775 throw new ObjectNotFoundException("The file contents could not be located");
780 public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
782 throw new ObjectNotFoundException("No user specified");
784 throw new ObjectNotFoundException("No file specified");
785 final User user = dao.getEntityById(User.class, userId);
786 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
787 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
788 throw new InsufficientPermissionsException("You don't have the necessary permissions");
789 return file.getDTO();
793 public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
795 throw new ObjectNotFoundException("No user specified");
797 throw new ObjectNotFoundException("No file specified");
798 User user = dao.getEntityById(User.class, userId);
799 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
800 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
801 throw new InsufficientPermissionsException("You don't have the necessary permissions");
802 FileBody body = dao.getEntityById(FileBody.class, bodyId);
803 return body.getDTO();
807 public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
808 throws ObjectNotFoundException {
810 throw new ObjectNotFoundException("No user specified");
811 if (StringUtils.isEmpty(path))
812 throw new ObjectNotFoundException("No path specified");
814 User owner = dao.getEntityById(User.class, ownerId);
815 List<String> pathElements = new ArrayList<String>();
816 StringTokenizer st = new StringTokenizer(path, "/");
817 while (st.hasMoreTokens())
818 pathElements.add(st.nextToken());
819 if (pathElements.size() < 1)
820 return getRootFolder(owner.getId());
821 // Store the last element, since it requires special handling.
822 String lastElement = pathElements.remove(pathElements.size() - 1);
823 FolderDTO cursor = getRootFolder(owner.getId());
824 // Traverse and verify the specified folder path.
825 for (String pathElement : pathElements) {
826 cursor = getFolder(cursor.getId(), pathElement);
827 if (cursor.isDeleted())
828 throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
831 // Use the lastElement to retrieve the actual resource.
832 Object resource = null;
834 FileHeaderDTO file = getFile(cursor.getId(), lastElement);
835 if (ignoreDeleted && file.isDeleted())
836 throw new ObjectNotFoundException("Resource not found");
838 } catch (ObjectNotFoundException e) {
839 // Perhaps the requested resource is not a file, so
840 // check for folders as well.
841 FolderDTO folder = getFolder(cursor.getId(), lastElement);
842 if (ignoreDeleted && folder.isDeleted())
843 throw new ObjectNotFoundException("Resource not found");
850 * Retrieve a file for the specified user that has the specified name and
851 * its parent folder has id equal to folderId.
853 * @param userId the ID of the current user
854 * @param folderId the ID of the parent folder
855 * @param name the name of the requested file
856 * @return the file found
857 * @throws ObjectNotFoundException if the specified folder or file was not
858 * found, with the exception message mentioning the precise
861 private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
862 if (folderId == null)
863 throw new ObjectNotFoundException("No parent folder specified");
864 if (StringUtils.isEmpty(name))
865 throw new ObjectNotFoundException("No file specified");
867 FileHeader file = dao.getFile(folderId, name);
868 return file.getDTO();
872 * Retrieve a folder for the specified user that has the specified name and
873 * its parent folder has id equal to parentId.
875 * @param parentId the ID of the parent folder
876 * @param name the name of the requested folder
877 * @return the folder found
878 * @throws ObjectNotFoundException if the specified folder or parent was not
879 * found, with the exception message mentioning the precise
882 private FolderDTO getFolder(Long parentId, String name) throws ObjectNotFoundException {
883 if (parentId == null)
884 throw new ObjectNotFoundException("No parent folder specified");
885 if (StringUtils.isEmpty(name))
886 throw new ObjectNotFoundException("No folder specified");
888 Folder folder = dao.getFolder(parentId, name);
889 return folder.getDTO();
892 private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
895 file = uploadFile(resourceInputStream, userId);
896 } catch ( IOException ioe) {
897 // Supply a more accurate problem description.
898 throw new GSSIOException("Problem creating file",ioe);
900 return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
904 public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
906 throw new ObjectNotFoundException("No user specified");
908 throw new ObjectNotFoundException("No file specified");
909 if (StringUtils.isEmpty(dest))
910 throw new ObjectNotFoundException("No destination specified");
912 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
913 if (!(destination instanceof FolderDTO))
914 throw new ObjectNotFoundException("Destination parent folder not found");
915 FolderDTO parent = (FolderDTO) destination;
916 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
920 public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
922 throw new ObjectNotFoundException("No user specified");
924 throw new ObjectNotFoundException("No owner specified");
926 throw new ObjectNotFoundException("No file specified");
927 if (StringUtils.isEmpty(dest))
928 throw new ObjectNotFoundException("No destination specified");
930 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
931 if (!(destination instanceof FolderDTO))
932 throw new ObjectNotFoundException("Destination parent folder not found");
933 FolderDTO parent = (FolderDTO) destination;
934 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
938 public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
940 throw new ObjectNotFoundException("No user specified");
942 throw new ObjectNotFoundException("No file specified");
944 throw new ObjectNotFoundException("No destination specified");
945 if (StringUtils.isEmpty(destName))
946 throw new ObjectNotFoundException("No destination file name specified");
948 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
949 Folder destination = dao.getEntityById(Folder.class, destId);
950 User user = dao.getEntityById(User.class, userId);
951 if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
952 throw new InsufficientPermissionsException("You don't have the necessary permissions");
953 boolean versioned = file.isVersioned();
954 int versionsNumber = file.getBodies().size();
955 FileBody oldestBody = file.getBodies().get(0);
956 assert oldestBody != null;
957 File contents = new File(oldestBody.getStoredFilePath());
959 createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
960 FileHeader copiedFile = dao.getFile(destination.getId(), destName);
961 copiedFile.setVersioned(versioned);
963 if (versionsNumber > 1)
964 for (int i = 1; i < versionsNumber; i++) {
965 FileBody body = file.getBodies().get(i);
967 contents = new File(body.getStoredFilePath());
968 updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
970 List<FileTag> tags = file.getFileTags();
971 for (FileTag tag : tags)
972 createTag(userId, copiedFile.getId(), tag.getTag());
974 } catch (FileNotFoundException e) {
975 throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
981 public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
983 throw new ObjectNotFoundException("No user specified");
984 if (folderId == null)
985 throw new ObjectNotFoundException("No folder specified");
986 if (StringUtils.isEmpty(dest))
987 throw new ObjectNotFoundException("No destination specified");
989 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
990 if (!(destination instanceof FolderDTO))
991 throw new ObjectNotFoundException("Destination folder not found");
992 FolderDTO parent = (FolderDTO) destination;
993 copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
997 public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
999 throw new ObjectNotFoundException("No user specified");
1000 if (folderId == null)
1001 throw new ObjectNotFoundException("No folder specified");
1003 throw new ObjectNotFoundException("No destination specified");
1004 if (StringUtils.isEmpty(destName))
1005 throw new ObjectNotFoundException("No destination folder name specified");
1006 Folder folder = dao.getEntityById(Folder.class, folderId);
1007 Folder destination = dao.getEntityById(Folder.class, destId);
1008 User user = dao.getEntityById(User.class, userId);
1009 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1010 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1011 createFolder(user.getId(), destination.getId(), destName);
1015 public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1017 throw new ObjectNotFoundException("No user specified");
1018 if (ownerId == null)
1019 throw new ObjectNotFoundException("No owner specified");
1020 if (folderId == null)
1021 throw new ObjectNotFoundException("No folder specified");
1022 if (StringUtils.isEmpty(dest))
1023 throw new ObjectNotFoundException("No destination specified");
1025 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1026 if (!(destination instanceof FolderDTO))
1027 throw new ObjectNotFoundException("Destination folder not found");
1028 FolderDTO parent = (FolderDTO) destination;
1029 copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1033 public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1035 throw new ObjectNotFoundException("No user specified");
1036 if (folderId == null)
1037 throw new ObjectNotFoundException("No folder specified");
1039 throw new ObjectNotFoundException("No destination specified");
1040 if (StringUtils.isEmpty(destName))
1041 throw new ObjectNotFoundException("No destination folder name specified");
1043 Folder folder = dao.getEntityById(Folder.class, folderId);
1044 Folder destination = dao.getEntityById(Folder.class, destId);
1045 final User user = dao.getEntityById(User.class, userId);
1046 // XXX: quick fix need to copy only visible items to user (Source
1048 if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1050 if(folder.isDeleted())//do not copy trashed folder and contents
1052 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1053 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1054 createFolder(user.getId(), destination.getId(), destName);
1055 Folder createdFolder = dao.getFolder(destination.getId(), destName);
1056 List<FileHeader> files = folder.getFiles();
1058 for (FileHeader file : files)
1059 if(!file.isDeleted())
1060 copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1061 List<Folder> subFolders = folder.getSubfolders();
1062 if (subFolders != null)
1063 for (Folder sub : subFolders)
1064 if(!sub.getId().equals(createdFolder.getId()))
1065 copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1070 * For a provided path, remove the last element and return the rest, that is
1071 * the path of the parent folder.
1073 * @param path the specified path
1074 * @return the path of the parent folder
1075 * @throws ObjectNotFoundException if the provided string contains no path
1078 private String getParentPath(String path) throws ObjectNotFoundException {
1079 int lastDelimiter = path.lastIndexOf('/');
1080 if (lastDelimiter == 0)
1082 if (lastDelimiter == -1)
1084 throw new ObjectNotFoundException("There is no parent in the path: " + path);
1085 else if (lastDelimiter < path.length() - 1)
1086 // Return the part before the delimiter.
1087 return path.substring(0, lastDelimiter);
1089 // Remove the trailing delimiter and then recurse.
1090 String strippedTrail = path.substring(0, lastDelimiter);
1091 return getParentPath(strippedTrail);
1096 * Get the last element in a path that denotes the file or folder name.
1098 * @param path the provided path
1099 * @return the last element in the path
1101 private String getLastElement(String path) {
1102 int lastDelimiter = path.lastIndexOf('/');
1103 if (lastDelimiter == -1)
1106 else if (lastDelimiter < path.length() - 1)
1107 // Return the part after the delimiter.
1108 return path.substring(lastDelimiter + 1);
1110 // Remove the trailing delimiter and then recurse.
1111 String strippedTrail = path.substring(0, lastDelimiter);
1112 return getLastElement(strippedTrail);
1117 public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1119 throw new ObjectNotFoundException("No user specified");
1121 throw new ObjectNotFoundException("No file specified");
1123 // Do the actual work.
1124 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1125 Folder parent = file.getFolder();
1127 throw new ObjectNotFoundException("The specified file has no parent folder");
1128 User user = dao.getEntityById(User.class, userId);
1129 if (!file.hasDeletePermission(user))
1130 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1132 file.setDeleted(true);
1134 touchParentFolders(parent, user, new Date());
1138 public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1140 throw new ObjectNotFoundException("No user specified");
1141 if (ownerId == null)
1142 throw new ObjectNotFoundException("No owner specified");
1144 throw new ObjectNotFoundException("No file specified");
1145 if (StringUtils.isEmpty(dest))
1146 throw new ObjectNotFoundException("No destination specified");
1148 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1149 if (!(destination instanceof FolderDTO))
1150 throw new ObjectNotFoundException("Destination parent folder not found");
1151 FolderDTO parent = (FolderDTO) destination;
1152 moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1156 public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1158 throw new ObjectNotFoundException("No user specified");
1160 throw new ObjectNotFoundException("No file specified");
1162 throw new ObjectNotFoundException("No destination specified");
1163 if (StringUtils.isEmpty(destName))
1164 throw new ObjectNotFoundException("No destination file name specified");
1166 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1167 Folder source = file.getFolder();
1168 Folder destination = dao.getEntityById(Folder.class, destId);
1170 User owner = dao.getEntityById(User.class, userId);
1171 if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1172 throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1174 // if the destination folder belongs to another user:
1175 if (!file.getOwner().equals(destination.getOwner())) {
1176 // (a) check if the destination quota allows the move
1177 if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1178 throw new QuotaExceededException("Not enough free space available");
1179 User newOwner = destination.getOwner();
1180 // (b) if quota OK, change the owner of the file
1181 file.setOwner(newOwner);
1182 // if the file has no permission for the new owner, add it
1183 Permission ownerPermission = null;
1184 for (final Permission p : file.getPermissions())
1185 if (p.getUser() != null)
1186 if (p.getUser().equals(newOwner)) {
1187 ownerPermission = p;
1190 if (ownerPermission == null) {
1191 ownerPermission = new Permission();
1192 ownerPermission.setUser(newOwner);
1193 file.addPermission(ownerPermission);
1195 ownerPermission.setRead(true);
1196 ownerPermission.setWrite(true);
1197 ownerPermission.setModifyACL(true);
1199 // move the file to the destination folder
1200 file.setFolder(destination);
1201 touchParentFolders(source, owner, new Date());
1202 touchParentFolders(destination, owner, new Date());
1206 public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1208 throw new ObjectNotFoundException("No user specified");
1209 if (ownerId == null)
1210 throw new ObjectNotFoundException("No owner specified");
1211 if (folderId == null)
1212 throw new ObjectNotFoundException("No folder specified");
1213 if (StringUtils.isEmpty(dest))
1214 throw new ObjectNotFoundException("No destination specified");
1216 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1217 if (!(destination instanceof FolderDTO))
1218 throw new ObjectNotFoundException("Destination parent folder not found");
1219 FolderDTO parent = (FolderDTO) destination;
1220 moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1224 public void moveFolder(Long userId, Long folderId, Long destId, String destName)
1225 throws ObjectNotFoundException, InsufficientPermissionsException,
1226 QuotaExceededException {
1227 Folder source = dao.getEntityById(Folder.class, folderId);
1228 Folder destination = dao.getEntityById(Folder.class, destId);
1229 User user = dao.getEntityById(User.class, userId);
1230 User sourceOwner = source.getOwner();
1231 User destinationOwner = destination.getOwner();
1232 // Do not move trashed folders and contents.
1233 if (source.isDeleted())
1235 // Check permissions.
1236 if (!destination.hasWritePermission(user)
1237 || !source.hasReadPermission(user)
1238 || !source.hasWritePermission(user))
1239 throw new InsufficientPermissionsException("You don't have the " +
1240 "necessary permissions");
1241 // Use the same timestamp for all subsequent modifications to make
1242 // changes appear simultaneous.
1243 Date now = new Date();
1244 // If source and destination are not in the same user's namespace,
1245 // change owners and check quota.
1246 if (!sourceOwner.equals(destinationOwner)) {
1247 changeOwner(source, destinationOwner, user, now);
1248 if (getQuotaLeft(destinationOwner.getId()) < 0)
1249 throw new QuotaExceededException("Not enough free space " +
1250 "available in destination folder");
1252 // Perform the move.
1253 Folder oldParent = source.getParent();
1254 oldParent.removeSubfolder(source);
1255 destination.addSubfolder(source);
1256 // Mark the former parent and destination trees upwards as modified.
1257 touchParentFolders(oldParent, user, now);
1258 touchParentFolders(source, user, now);
1262 * Recursively change the owner of the specified folder and all of its
1263 * contents to the specified owner. Also mark them all as modified with the
1264 * specified modifier and modificationDate.
1266 private void changeOwner(Folder folder, User owner, User modifier, Date modificationDate) {
1267 for (FileHeader file: folder.getFiles()) {
1268 file.setOwner(owner);
1269 file.getAuditInfo().setModificationDate(modificationDate);
1270 file.getAuditInfo().setModifiedBy(modifier);
1272 for (Folder sub: folder.getSubfolders())
1273 changeOwner(sub, owner, modifier, modificationDate);
1274 folder.setOwner(owner);
1275 folder.getAuditInfo().setModificationDate(modificationDate);
1276 folder.getAuditInfo().setModifiedBy(modifier);
1280 public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1283 throw new ObjectNotFoundException("No user specified");
1285 // Do the actual work.
1286 final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1287 final List<FileHeader> files = dao.getDeletedFiles(userId);
1288 for (final FileHeader f : files)
1289 result.add(f.getDTO());
1294 public void removeFileFromTrash(Long userId, Long fileId)
1295 throws ObjectNotFoundException, InsufficientPermissionsException {
1297 throw new ObjectNotFoundException("No user specified");
1299 throw new ObjectNotFoundException("No file specified");
1301 // Do the actual work.
1302 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1303 Folder parent = file.getFolder();
1305 throw new ObjectNotFoundException("The specified file has no parent folder");
1306 User user = dao.getEntityById(User.class, userId);
1307 if (!file.hasDeletePermission(user))
1308 throw new InsufficientPermissionsException("User " + user.getUsername() +
1309 " cannot restore file " + file.getName());
1311 file.setDeleted(false);
1313 touchParentFolders(parent, user, new Date());
1317 public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1319 throw new ObjectNotFoundException("No user specified");
1320 if (folderId == null)
1321 throw new ObjectNotFoundException("No folder specified");
1322 Folder folder = dao.getEntityById(Folder.class, folderId);
1323 User user = dao.getEntityById(User.class, userId);
1324 if (!folder.hasDeletePermission(user))
1325 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1326 folder.setDeleted(true);
1328 touchParentFolders(folder, user, new Date());
1329 for (FileHeader file : folder.getFiles())
1330 moveFileToTrash(userId, file.getId());
1331 for (Folder subFolder : folder.getSubfolders())
1332 moveFolderToTrash(userId, subFolder.getId());
1337 public void removeFolderFromTrash(Long userId, Long folderId)
1338 throws ObjectNotFoundException, InsufficientPermissionsException {
1340 throw new ObjectNotFoundException("No user specified");
1341 if (folderId == null)
1342 throw new ObjectNotFoundException("No folder specified");
1343 Folder folder = dao.getEntityById(Folder.class, folderId);
1344 User user = dao.getEntityById(User.class, userId);
1345 if (!folder.hasDeletePermission(user))
1346 throw new InsufficientPermissionsException("User " + user.getUsername() +
1347 " cannot restore folder " + folder.getName());
1348 folder.setDeleted(false);
1349 for (FileHeader file : folder.getFiles())
1350 removeFileFromTrash(userId, file.getId());
1351 for (Folder subFolder : folder.getSubfolders())
1352 removeFolderFromTrash(userId, subFolder.getId());
1354 touchParentFolders(folder, user, new Date());
1358 public List<FolderDTO> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1359 List<Folder> folders = dao.getDeletedRootFolders(userId);
1360 List<FolderDTO> result = new ArrayList<FolderDTO>();
1361 for (Folder folder : folders)
1362 result.add(folder.getDTO());
1367 public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1368 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1369 for (FolderDTO fdto : deletedRootFolders)
1370 deleteFolder(userId, fdto.getId());
1371 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1372 for (FileHeaderDTO filedto : deletedFiles)
1373 deleteFile(userId, filedto.getId());
1377 public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1378 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1379 for (FolderDTO fdto : deletedRootFolders)
1380 removeFolderFromTrash(userId, fdto.getId());
1381 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1382 for (FileHeaderDTO filedto : deletedFiles)
1383 removeFileFromTrash(userId, filedto.getId());
1387 public User createUser(String username, String name, String mail,
1388 String idp, String idpid) throws ObjectNotFoundException {
1389 if (username == null)
1390 throw new ObjectNotFoundException("No username specified");
1392 throw new ObjectNotFoundException("No name specified");
1394 User user = new User();
1395 user.setUsername(username);
1397 user.setEmail(mail);
1398 user.setIdentityProvider(idp);
1399 user.setIdentityProviderId(idpid);
1400 Date now = new Date();
1401 AuditInfo auditInfo = new AuditInfo();
1402 auditInfo.setCreationDate(now);
1403 auditInfo.setModificationDate(now);
1404 user.setAuditInfo(auditInfo);
1405 user.setActive(true);
1406 user.generateAuthToken();
1407 user.generateWebDAVPassword();
1408 user.setUserClass(getDefaultUserClass());
1410 // Make sure we get an ID in the user object.
1412 // Create the root folder for the user.
1413 createFolder(user.getName(), null, user);
1418 * Get the default user class, which is the one with the lowest quota.
1420 private UserClass getDefaultUserClass() {
1421 return getUserClasses().get(0);
1425 public List<UserClass> getUserClasses() {
1426 List<UserClass> classes = dao.getUserClasses();
1427 // Create a default user class for first-time use. Afterwards, the
1428 // admin should modify or add to the userclass table.
1429 if (classes.size() == 0) {
1430 UserClass defaultClass = new UserClass();
1431 defaultClass.setName("default");
1432 Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L));
1433 defaultClass.setQuota(defaultQuota);
1434 dao.create(defaultClass);
1435 classes.add(defaultClass);
1441 public User findUserByEmail(String email) {
1442 return dao.findUserByEmail(email);
1446 public void updateUser(User user) {
1451 public User findUser(String username) {
1452 if (username == null)
1454 return dao.findUser(username);
1458 public User updateUserToken(Long userId) throws ObjectNotFoundException {
1460 throw new ObjectNotFoundException("No user specified");
1461 User user = dao.getEntityById(User.class, userId);
1462 user.generateAuthToken();
1467 public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1469 throw new ObjectNotFoundException("No user specified");
1470 if (folderId == null)
1471 throw new ObjectNotFoundException("No folder specified");
1472 User user = dao.getEntityById(User.class, userId);
1473 Folder folder = dao.getEntityById(Folder.class, folderId);
1474 if(!folder.hasReadPermission(user))
1475 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1476 Set<Permission> perms = folder.getPermissions();
1477 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1478 for (Permission perm : perms)
1479 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1480 result.add(perm.getDTO());
1481 for (Permission perm : perms)
1482 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1484 result.add(perm.getDTO());
1490 * Set the provided permissions as the new permissions of the specified
1495 * @param permissions
1496 * @throws ObjectNotFoundException
1497 * @throws InsufficientPermissionsException
1499 private void setFolderPermissions(User user, Folder folder, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1500 if (permissions != null && !permissions.isEmpty()) {
1501 User owner = folder.getOwner();
1502 PermissionDTO ownerPerm = null;
1503 for (PermissionDTO dto : permissions)
1504 if (dto.getUser() != null && dto.getUser().getId().equals(owner.getId())) {
1508 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1509 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1510 // Delete previous entries
1511 for (Permission perm: folder.getPermissions())
1513 folder.getPermissions().clear();
1514 for (PermissionDTO dto : permissions) {
1515 // Skip 'empty' permission entries.
1516 if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1517 folder.addPermission(getPermission(dto));
1520 for (FileHeader file : folder.getFiles()) {
1521 setFilePermissions(file, permissions);
1522 Date now = new Date();
1523 file.getAuditInfo().setModificationDate(now);
1524 file.getAuditInfo().setModifiedBy(user);
1526 for (Folder sub : folder.getSubfolders())
1527 setFolderPermissions(user, sub, permissions);
1531 private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1532 Permission res = new Permission();
1533 if (dto.getGroup() != null)
1534 res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1535 else if (dto.getUser() != null)
1536 if (dto.getUser().getId() == null)
1537 res.setUser(dao.getUser(dto.getUser().getUsername()));
1539 res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1540 res.setRead(dto.hasRead());
1541 res.setWrite(dto.hasWrite());
1542 res.setModifyACL(dto.hasModifyACL());
1547 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1550 public List<UserDTO> getUsersByUserNameLike(String username) {
1551 List<User> users = dao.getUsersByUserNameLike(username);
1552 List<UserDTO> result = new ArrayList<UserDTO>();
1553 for (User u : users)
1554 result.add(u.getDTO());
1560 public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1562 throw new ObjectNotFoundException("No user specified");
1563 if (groupId == null)
1564 throw new ObjectNotFoundException("No group specified");
1565 if (userToAddId == null)
1566 throw new ObjectNotFoundException("No user to add specified");
1567 User user = dao.getEntityById(User.class, userId);
1568 Group group = dao.getEntityById(Group.class, groupId);
1569 if (!group.getOwner().equals(user))
1570 throw new InsufficientPermissionsException();
1571 User userToAdd = dao.getEntityById(User.class, userToAddId);
1572 if (group.contains(userToAdd))
1573 throw new DuplicateNameException("User already exists in group");
1574 group.getMembers().add(userToAdd);
1580 public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1582 throw new ObjectNotFoundException("No user specified");
1583 User user = dao.getEntityById(User.class, userId);
1584 user.invalidateAuthToken();
1589 public List<FolderDTO> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1591 throw new ObjectNotFoundException("No user specified");
1592 List<Folder> folders = dao.getSharedRootFolders(userId);
1593 List<FolderDTO> result = new ArrayList<FolderDTO>();
1594 for (Folder f : folders) {
1595 FolderDTO dto = f.getDTO();
1596 dto.setSubfolders(getSharedSubfolders(userId, f.getId()));
1603 public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1605 throw new ObjectNotFoundException("No user specified");
1606 if (groupId == null)
1607 throw new ObjectNotFoundException("No group specified");
1608 if (memberId == null)
1609 throw new ObjectNotFoundException("No member specified");
1610 User owner = dao.getEntityById(User.class, userId);
1611 Group group = dao.getEntityById(Group.class, groupId);
1612 User member = dao.getEntityById(User.class, memberId);
1613 if (!group.getOwner().equals(owner))
1614 throw new InsufficientPermissionsException("User is not the owner of the group");
1615 group.removeMemberFromGroup(member);
1621 public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1622 List<User> users = dao.getUsersSharingFoldersForUser(userId);
1623 List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1624 List<UserDTO> res = new ArrayList<UserDTO>();
1625 for (User u : users)
1626 res.add(u.getDTO());
1627 for(User fu : usersFiles)
1628 if(!users.contains(fu))
1629 res.add(fu.getDTO());
1634 public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1636 throw new ObjectNotFoundException("No user specified");
1638 throw new ObjectNotFoundException("No folder specified");
1639 User user = dao.getEntityById(User.class, userId);
1640 FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1641 if(!folder.hasReadPermission(user))
1642 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1643 Set<Permission> perms = folder.getPermissions();
1644 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1645 for (Permission perm : perms)
1646 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1647 result.add(perm.getDTO());
1648 for (Permission perm : perms)
1649 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1651 result.add(perm.getDTO());
1656 * Set the provided permissions as the new permissions of the specified
1657 * file. This method sets the modification date/user attributes to the
1658 * current values as a side effect.
1661 * @param permissions
1662 * @throws ObjectNotFoundException
1663 * @throws InsufficientPermissionsException
1665 private void setFilePermissions(FileHeader file,
1666 Set<PermissionDTO> permissions)
1667 throws ObjectNotFoundException, InsufficientPermissionsException {
1668 if (permissions != null && !permissions.isEmpty()) {
1669 PermissionDTO ownerPerm = null;
1670 for (PermissionDTO dto : permissions)
1671 if (dto.getUser() != null && dto.getUser().getId().equals(file.getOwner().getId())) {
1675 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1676 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1677 // Delete previous entries.
1678 for (Permission perm: file.getPermissions())
1680 file.getPermissions().clear();
1681 for (PermissionDTO dto : permissions) {
1682 // Skip 'empty' permission entries.
1683 if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1684 file.addPermission(getPermission(dto));
1691 public List<FileHeaderDTO> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1693 throw new ObjectNotFoundException("No user specified");
1694 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1695 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1696 for (FileHeader f : files)
1697 result.add(f.getDTO());
1702 public List<FileHeaderDTO> getSharedFiles(Long userId) throws ObjectNotFoundException {
1704 throw new ObjectNotFoundException("No user specified");
1705 List<FileHeader> files = dao.getSharedFiles(userId);
1706 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1707 for (FileHeader f : files)
1708 result.add(f.getDTO());
1713 public List<FolderDTO> getSharedFolders(Long userId) throws ObjectNotFoundException {
1715 throw new ObjectNotFoundException("No user specified");
1716 List<Folder> folders = dao.getSharedFolders(userId);
1717 List<FolderDTO> result = new ArrayList<FolderDTO>();
1718 for (Folder f : folders)
1719 result.add(f.getDTO());
1724 public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1725 if (ownerId == null)
1726 throw new ObjectNotFoundException("No owner specified");
1727 if (callingUserId == null)
1728 throw new ObjectNotFoundException("No calling user specified");
1729 List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1730 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1731 for (FileHeader f : folders)
1732 result.add(f.getDTO());
1737 public List<FolderDTO> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1738 if (ownerId == null)
1739 throw new ObjectNotFoundException("No owner specified");
1740 if (callingUserId == null)
1741 throw new ObjectNotFoundException("No calling user specified");
1742 List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1743 List<FolderDTO> result = new ArrayList<FolderDTO>();
1744 for (Folder f : folders) {
1745 FolderDTO dto = f.getDTO();
1746 dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1754 public List<FolderDTO> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1756 throw new ObjectNotFoundException("No user specified");
1757 if (folderId == null)
1758 throw new ObjectNotFoundException("No folder specified");
1759 User user = dao.getEntityById(User.class, userId);
1760 Folder folder = dao.getEntityById(Folder.class, folderId);
1761 List<FolderDTO> result = new ArrayList<FolderDTO>();
1762 if (folder.isShared(user))
1763 for (Folder f : folder.getSubfolders())
1764 if (f.isShared(user) && !f.isDeleted())
1765 result.add(f.getDTO());
1770 public List<FolderDTO> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1772 throw new ObjectNotFoundException("No user specified");
1773 if (callingUserId == null)
1774 throw new ObjectNotFoundException("No user specified");
1775 if (folderId == null)
1776 throw new ObjectNotFoundException("No folder specified");
1777 User user = dao.getEntityById(User.class, callingUserId);
1778 Folder folder = dao.getEntityById(Folder.class, folderId);
1779 List<FolderDTO> result = new ArrayList<FolderDTO>();
1780 if (folder.isSharedForOtherUser(user))
1781 for (Folder f : folder.getSubfolders())
1782 if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1783 FolderDTO dto = f.getDTO();
1784 dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId()));
1792 public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1794 throw new ObjectNotFoundException("No user specified");
1795 User user = getUser(userId);
1797 throw new ObjectNotFoundException("No query specified");
1798 List<FileHeader> files = search(user.getId(), query);
1799 List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1800 for(FileHeader f : files)
1801 res.add(f.getDTO());
1806 * Performs the actuals search on the solr server and returns the results
1808 * We have to use the dismax query type (instead of the
1809 * standard) because it allows for search time field boosting. This is because we can't use indexing
1810 * time field boosting due to the patched rich indexing API that does not allow it
1814 * @return a List of FileHeader objects
1816 private List<FileHeader> search(Long userId, String query) {
1818 HttpClient httpClient = new HttpClient();
1820 GetMethod method = new GetMethod(getConfiguration().getString("solrSelectUrl"));
1821 NameValuePair[] params = {new NameValuePair("qt", "dismax"),
1822 new NameValuePair("q", query),
1823 new NameValuePair("sort", "score desc"),
1824 new NameValuePair("indent", "on")};
1825 method.setQueryString(params);
1828 String response = null;
1830 statusCode = httpClient.executeMethod(method);
1831 logger.debug("HTTP status: " + statusCode);
1832 response = method.getResponseBodyAsString();
1833 logger.debug(response);
1835 if (statusCode != 200 && retryCount < 3)
1837 Thread.sleep(3000); //Give Solr a little time to be available
1838 } catch (InterruptedException e) {
1840 } while (statusCode != 200 && retryCount < 3);
1841 if (statusCode != 200)
1842 throw new EJBException("Search query return error:\n" + response);
1844 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1845 DocumentBuilder db = dbf.newDocumentBuilder();
1846 Document doc = db.parse(method.getResponseBodyAsStream());
1847 method.releaseConnection();
1849 Node root = doc.getElementsByTagName("response").item(0);
1850 Node lst = root.getFirstChild().getNextSibling();
1851 Node status = lst.getFirstChild().getNextSibling();
1852 if (status.getAttributes().getNamedItem("name").getNodeValue().equals("status") &&
1853 status.getTextContent().equals("0")) {
1854 List<FileHeader> fileResult = new ArrayList<FileHeader>();
1855 Node result = lst.getNextSibling().getNextSibling();
1856 NodeList docs = result.getChildNodes();
1857 User user = getUser(userId);
1858 for (int i=1; i<docs.getLength(); i=i+2) {
1859 Node d = docs.item(i);
1860 NodeList docData = d.getChildNodes();
1861 for (int j=1; j<docData.getLength(); j=j+2) {
1862 Node dd = docData.item(j);
1863 if (dd.getAttributes().item(0).getNodeName().equals("name") &&
1864 dd.getAttributes().item(0).getNodeValue().equals("id")) {
1865 Long fileId = Long.valueOf(dd.getTextContent());
1867 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1868 if (file.hasReadPermission(user)) {
1869 fileResult.add(file);
1870 logger.debug("File added " + fileId);
1872 } catch (ObjectNotFoundException e) {
1873 logger.warn("Search result not found", e);
1880 throw new EJBException();
1881 } catch (HttpException e) {
1882 throw new EJBException(e);
1883 } catch (IOException e) {
1884 throw new EJBException(e);
1885 } catch (SAXException e) {
1886 throw new EJBException(e);
1887 } catch (ParserConfigurationException e) {
1888 throw new EJBException(e);
1889 } catch (ObjectNotFoundException e) {
1890 throw new EJBException(e);
1895 public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1896 for(Long l : fileIds){
1897 FileHeader file = dao.getEntityById(FileHeader.class, l);
1898 copyFile(userId, l, destId, file.getName());
1905 public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1906 for(Long l : fileIds){
1907 FileHeader file = dao.getEntityById(FileHeader.class, l);
1908 moveFile(userId, l, destId, file.getName());
1914 public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1916 throw new ObjectNotFoundException("No user specified");
1917 final User user = dao.getEntityById(User.class, userId);
1918 List<String> filesToRemove = new ArrayList<String>();
1919 //first delete database objects
1920 for(Long fileId : fileIds){
1922 throw new ObjectNotFoundException("No file specified");
1923 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1924 final Folder parent = file.getFolder();
1926 throw new ObjectNotFoundException("The specified file has no parent folder");
1927 if (!file.hasDeletePermission(user))
1928 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1930 parent.removeFile(file);
1931 for (final FileBody body : file.getBodies())
1932 filesToRemove.add(body.getStoredFilePath());
1934 touchParentFolders(parent, user, new Date());
1936 //then remove physical files if everything is ok
1937 for(String physicalFileName : filesToRemove)
1938 deleteActualFile(physicalFileName);
1939 //then unindex deleted files
1940 for(Long fileId : fileIds)
1941 indexFile(fileId, true);
1946 public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1947 for(Long l : fileIds)
1948 moveFileToTrash(userId, l);
1953 public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1954 for(Long l : fileIds)
1955 removeFileFromTrash(userId, l);
1960 public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1962 throw new ObjectNotFoundException("No user specified");
1963 User user = dao.getEntityById(User.class, userId);
1964 Nonce nonce = Nonce.createNonce(user.getId());
1970 public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1972 throw new ObjectNotFoundException("No user specified");
1974 throw new ObjectNotFoundException("No nonce specified");
1975 return dao.getNonce(nonce, userId);
1979 public void removeNonce(Long id) throws ObjectNotFoundException {
1981 throw new ObjectNotFoundException("No nonce specified");
1982 Nonce nonce = dao.getEntityById(Nonce.class, id);
1987 public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1989 throw new ObjectNotFoundException("No user specified");
1990 User user = dao.getEntityById(User.class, userId);
1991 user.setNonce(nonce);
1992 user.setNonceExpiryDate(nonceExpiryDate);
1996 public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1998 throw new ObjectNotFoundException("No user specified");
1999 StatsDTO stats = new StatsDTO();
2000 stats.setFileCount(dao.getFileCount(userId));
2001 Long fileSize = dao.getFileSize(userId);
2002 stats.setFileSize(fileSize);
2003 Long quota = getQuota(userId);
2004 Long quotaLeft = quota - fileSize;
2005 stats.setQuotaLeftSize(quotaLeft);
2010 public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2012 throw new ObjectNotFoundException("No user specified");
2014 throw new ObjectNotFoundException("No file specified");
2015 User user = dao.getEntityById(User.class, userId);
2016 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2017 if(!header.hasReadPermission(user))
2018 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2019 List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
2020 for(int i = header.getBodies().size()-1 ; i>=0; i--)
2021 result.add(header.getBodies().get(i).getDTO());
2026 public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
2028 throw new ObjectNotFoundException("No user specified");
2030 throw new ObjectNotFoundException("No file specified");
2032 throw new ObjectNotFoundException("No body specified");
2033 User user = dao.getEntityById(User.class, userId);
2034 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2035 if(!header.hasWritePermission(user))
2036 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2037 FileBody body = dao.getEntityById(FileBody.class, bodyId);
2038 if(body.equals(header.getCurrentBody())){
2040 if(header.getBodies().size() == 1)
2041 throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
2042 for(FileBody b : header.getBodies())
2043 if(b.getVersion() == body.getVersion()-1)
2044 header.setCurrentBody(b);
2046 deleteActualFile(body.getStoredFilePath());
2047 header.getBodies().remove(body);
2049 Folder parent = header.getFolder();
2050 touchParentFolders(parent, user, new Date());
2055 public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
2057 throw new ObjectNotFoundException("No user specified");
2059 throw new ObjectNotFoundException("No file specified");
2060 User user = dao.getEntityById(User.class, userId);
2061 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2062 if(!header.hasWritePermission(user))
2063 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2064 FileBody body = dao.getFileVersion(fileId, version);
2065 final File fileContents = new File(body.getStoredFilePath());
2068 updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
2069 } catch (FileNotFoundException e) {
2070 throw new GSSIOException(e);
2076 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2079 public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2081 throw new ObjectNotFoundException("No user specified");
2083 throw new ObjectNotFoundException("No file specified");
2084 User user = dao.getEntityById(User.class, userId);
2085 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2086 if(!header.hasWritePermission(user))
2087 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2088 Iterator<FileBody> it = header.getBodies().iterator();
2089 while(it.hasNext()){
2090 FileBody body = it.next();
2091 if(!body.equals(header.getCurrentBody())){
2092 deleteActualFile(body.getStoredFilePath());
2097 header.getCurrentBody().setVersion(1);
2099 Folder parent = header.getFolder();
2100 touchParentFolders(parent, user, new Date());
2104 * Gets the quota left for specified user ID.
2106 private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
2107 Long fileSize = dao.getFileSize(userId);
2108 Long quota = getQuota(userId);
2109 return quota - fileSize;
2113 * Gets the quota for specified user ID.
2115 private Long getQuota(Long userId) throws ObjectNotFoundException{
2116 UserClass uc = getUser(userId).getUserClass();
2118 uc = getDefaultUserClass();
2119 return uc.getQuota();
2123 public void rebuildSolrIndex() {
2124 MessageProducer sender = null;
2125 Session session = null;
2126 Connection qConn = null;
2128 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2129 DocumentBuilder db = dbf.newDocumentBuilder();
2130 Document doc = db.newDocument();
2131 Node root = doc.createElement("delete");
2132 doc.appendChild(root);
2133 Node queryNode = doc.createElement("query");
2134 root.appendChild(queryNode);
2135 queryNode.appendChild(doc.createTextNode("*:*"));
2137 TransformerFactory fact = TransformerFactory.newInstance();
2138 Transformer trans = fact.newTransformer();
2139 trans.setOutputProperty(OutputKeys.INDENT, "yes");
2140 StringWriter sw = new StringWriter();
2141 StreamResult sr = new StreamResult(sw);
2142 DOMSource source = new DOMSource(doc);
2143 trans.transform(source, sr);
2144 logger.debug(sw.toString());
2146 HttpClient httpClient = new HttpClient();
2147 PostMethod method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2148 method.setRequestEntity(new StringRequestEntity(sw.toString()));
2151 String response = null;
2153 statusCode = httpClient.executeMethod(method);
2154 logger.debug("HTTP status: " + statusCode);
2155 response = method.getResponseBodyAsString();
2156 logger.debug(response);
2158 if (statusCode != 200 && retryCount < 3)
2160 Thread.sleep(10000); //Give Solr a little time to be available
2161 } catch (InterruptedException e) {
2163 } while (statusCode != 200 && retryCount < 3);
2164 method.releaseConnection();
2165 if (statusCode != 200)
2166 throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response);
2167 List<Long> fileIds = dao.getAllFileIds();
2169 Context jndiCtx = new InitialContext();
2170 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
2171 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
2172 qConn = factory.createConnection();
2173 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
2174 sender = session.createProducer(queue);
2176 for (Long id : fileIds) {
2177 MapMessage map = session.createMapMessage();
2178 map.setObject("id", id);
2179 map.setBoolean("delete", false);
2182 sendOptimize(httpClient, 0);
2183 } catch (DOMException e) {
2184 throw new EJBException(e);
2185 } catch (TransformerConfigurationException e) {
2186 throw new EJBException(e);
2187 } catch (IllegalArgumentException e) {
2188 throw new EJBException(e);
2189 } catch (HttpException e) {
2190 throw new EJBException(e);
2191 } catch (UnsupportedEncodingException e) {
2192 throw new EJBException(e);
2193 } catch (ParserConfigurationException e) {
2194 throw new EJBException(e);
2195 } catch (TransformerException e) {
2196 throw new EJBException(e);
2197 } catch (IOException e) {
2198 throw new EJBException(e);
2199 } catch (NamingException e) {
2200 throw new EJBException(e);
2201 } catch (JMSException e) {
2202 throw new EJBException(e);
2208 if (session != null)
2213 catch (JMSException e) {
2220 * Sends a optimize message to the solr server
2223 * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive
2224 * calls to stop the recursion
2225 * @throws UnsupportedEncodingException
2226 * @throws IOException
2227 * @throws HttpException
2229 private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException {
2230 PostMethod method = null;
2232 logger.debug("Optimize retry: " + retryCount);
2233 method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2234 method.setRequestEntity(new StringRequestEntity("<optimize/>", "text/xml", "iso8859-1"));
2235 int statusCode = httpClient.executeMethod(method);
2236 logger.debug("HTTP status: " + statusCode);
2237 String response = method.getResponseBodyAsString();
2238 logger.debug(response);
2239 if (statusCode != 200 && retryCount < 2) {
2241 Thread.sleep(10000); //Give Solr a little time to be available
2242 } catch (InterruptedException e) {
2244 sendOptimize(httpClient, retryCount + 1);
2249 method.releaseConnection();
2254 public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2255 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2256 InsufficientPermissionsException, QuotaExceededException {
2259 throw new ObjectNotFoundException("No user specified");
2260 if (folderId == null)
2261 throw new ObjectNotFoundException("No folder specified");
2262 String contentType = mimeType;
2263 if (StringUtils.isEmpty(mimeType))
2264 contentType = DEFAULT_MIME_TYPE;
2265 if (StringUtils.isEmpty(name))
2266 throw new ObjectNotFoundException("No file name specified");
2267 if (dao.existsFolderOrFile(folderId, name))
2268 throw new DuplicateNameException("A folder or file with the name '" + name +
2269 "' already exists at this level");
2271 // Do the actual work.
2272 Folder parent = null;
2274 parent = dao.getEntityById(Folder.class, folderId);
2275 } catch (final ObjectNotFoundException onfe) {
2276 // Supply a more accurate problem description.
2277 throw new ObjectNotFoundException("Parent folder not found");
2279 final User owner = dao.getEntityById(User.class, userId);
2280 if (!parent.hasWritePermission(owner))
2281 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2282 final FileHeader file = new FileHeader();
2284 parent.addFile(file);
2285 // set file owner to folder owner
2286 file.setOwner(parent.getOwner());
2288 final Date now = new Date();
2289 final AuditInfo auditInfo = new AuditInfo();
2290 auditInfo.setCreatedBy(owner);
2291 auditInfo.setCreationDate(now);
2292 auditInfo.setModifiedBy(owner);
2293 auditInfo.setModificationDate(now);
2294 file.setAuditInfo(auditInfo);
2295 // TODO set the proper versioning flag on creation
2296 file.setVersioned(false);
2298 for (final Permission p : parent.getPermissions()) {
2299 final Permission permission = new Permission();
2300 permission.setGroup(p.getGroup());
2301 permission.setUser(p.getUser());
2302 permission.setRead(p.getRead());
2303 permission.setWrite(p.getWrite());
2304 permission.setModifyACL(p.getModifyACL());
2305 file.addPermission(permission);
2308 // Create the file body.
2310 createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2311 } catch (FileNotFoundException e) {
2312 throw new GSSIOException(e);
2314 touchParentFolders(parent, owner, new Date());
2316 indexFile(file.getId(), false);
2318 return file.getDTO();
2322 public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2324 throw new ObjectNotFoundException("No user specified");
2326 throw new ObjectNotFoundException("No file specified");
2327 String contentType = mimeType;
2329 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2331 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2332 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2333 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2334 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2335 contentType = identifyMimeType(file.getName());
2337 final User owner = dao.getEntityById(User.class, userId);
2338 if (!file.hasWritePermission(owner))
2339 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2340 final Date now = new Date();
2341 final AuditInfo auditInfo = new AuditInfo();
2342 auditInfo.setCreatedBy(owner);
2343 auditInfo.setCreationDate(now);
2344 auditInfo.setModifiedBy(owner);
2345 auditInfo.setModificationDate(now);
2347 createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2348 } catch (FileNotFoundException e) {
2349 throw new GSSIOException(e);
2351 Folder parent = file.getFolder();
2352 touchParentFolders(parent, owner, new Date());
2354 indexFile(fileId, false);
2355 return file.getDTO();
2359 * Helper method for identifying mime type by examining the filename extension
2362 * @return the mime type
2364 private String identifyMimeType(String filename) {
2365 if (filename.indexOf('.') != -1) {
2366 String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2367 if (".doc".equals(extension))
2368 return "application/msword";
2369 else if (".xls".equals(extension))
2370 return "application/vnd.ms-excel";
2371 else if (".ppt".equals(extension))
2372 return "application/vnd.ms-powerpoint";
2373 else if (".pdf".equals(extension))
2374 return "application/pdf";
2375 else if (".gif".equals(extension))
2377 else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2378 return "image/jpeg";
2379 else if (".tiff".equals(extension) || ".tif".equals(extension))
2380 return "image/tiff";
2381 else if (".png".equals(extension))
2383 else if (".bmp".equals(extension))
2386 // when all else fails assign the default mime type
2387 return DEFAULT_MIME_TYPE;
2391 * Helper method to create a new file body and attach it as the current body
2392 * of the provided file header.
2394 * @param name the original file name
2395 * @param mimeType the content type
2396 * @param fileSize the uploaded file size
2397 * @param filePath the uploaded file full path
2398 * @param header the file header that will be associated with the new body
2399 * @param auditInfo the audit info
2400 * @param owner the owner of the file
2401 * @throws FileNotFoundException
2402 * @throws QuotaExceededException
2403 * @throws ObjectNotFoundException if the owner was not found
2405 private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2406 FileHeader header, AuditInfo auditInfo)
2407 throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2409 long currentTotalSize = 0;
2410 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2411 currentTotalSize = header.getTotalSize();
2412 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2413 if(quotaLeft < fileSize-currentTotalSize) {
2414 // quota exceeded -> delete the file
2415 deleteActualFile(filePath);
2416 throw new QuotaExceededException("Not enough free space available");
2419 FileBody body = new FileBody();
2421 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2422 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2423 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2424 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2425 body.setMimeType(identifyMimeType(name));
2427 body.setMimeType(mimeType);
2428 body.setAuditInfo(auditInfo);
2429 body.setFileSize(fileSize);
2430 body.setOriginalFilename(name);
2431 body.setStoredFilePath(filePath);
2432 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2433 if(!header.isVersioned() && header.getCurrentBody() != null){
2434 header.setCurrentBody(null);
2435 if (header.getBodies() != null) {
2436 Iterator<FileBody> it = header.getBodies().iterator();
2437 while(it.hasNext()){
2438 FileBody bo = it.next();
2439 deleteActualFile(bo.getStoredFilePath());
2447 header.addBody(body);
2448 header.setAuditInfo(auditInfo);
2455 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2456 public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2458 throw new ObjectNotFoundException("No user specified");
2459 User owner = dao.getEntityById(User.class, userId);
2461 throw new ObjectNotFoundException("No user specified");
2462 long start = 0, end = 0;
2463 if (logger.isDebugEnabled())
2464 start = System.currentTimeMillis();
2465 File result = new File(generateRepositoryFilePath());
2467 final FileOutputStream output = new FileOutputStream(result);
2468 final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2471 while (-1 != (n = stream.read(buffer)))
2472 output.write(buffer, 0, n);
2475 } catch (IOException e) {
2476 if (!result.delete())
2477 logger.warn("Could not delete " + result.getPath());
2480 if (logger.isDebugEnabled()) {
2481 end = System.currentTimeMillis();
2482 logger.debug("Time to upload: " + (end - start) + " (msec)");
2489 public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2492 throw new ObjectNotFoundException("No user specified");
2493 User user = dao.getEntityById(User.class, userId);
2494 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2496 status = new FileUploadStatus();
2497 status.setOwner(user);
2498 status.setFilename(filename);
2499 status.setBytesUploaded(bytesTransfered);
2500 status.setFileSize(fileSize);
2504 status.setBytesUploaded(bytesTransfered);
2505 status.setFileSize(fileSize);
2512 public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2514 throw new ObjectNotFoundException("No user specified");
2515 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2521 public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2522 return dao.getFileUploadStatus(userId, fileName);
2526 public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2528 throw new ObjectNotFoundException("No user specified");
2529 if (folderId == null)
2530 throw new ObjectNotFoundException("No folder specified");
2531 final User user = dao.getEntityById(User.class, userId);
2532 final Folder folder = dao.getEntityById(Folder.class, folderId);
2533 // Check permissions
2534 if (!folder.hasReadPermission(user))
2535 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2536 List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2537 if (folder.hasReadPermission(user))
2538 for (Folder f : folder.getSubfolders())
2539 if (f.hasReadPermission(user) && !f.isDeleted())
2540 subfolders.add(f.getDTO());
2541 FolderDTO result = folder.getDTO();
2542 result.setSubfolders(subfolders);
2543 return folder.getDTO();
2547 public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2549 throw new ObjectNotFoundException("No user specified");
2550 if (folderId == null)
2551 throw new ObjectNotFoundException("No folder specified");
2552 User user = dao.getEntityById(User.class, callingUserId);
2553 Folder folder = dao.getEntityById(Folder.class, folderId);
2554 // Check permissions
2555 if (!folder.hasReadPermission(user))
2556 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2558 FolderDTO result = folder.getDTO();
2559 result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2564 public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2565 throws ObjectNotFoundException, InsufficientPermissionsException {
2567 throw new ObjectNotFoundException("No user specified");
2569 throw new ObjectNotFoundException("No file specified");
2571 throw new ObjectNotFoundException("No valid version specified");
2572 User user = dao.getEntityById(User.class, userId);
2573 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2574 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2575 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2576 FileBody body = dao.getFileVersion(fileId, version);
2577 return body.getDTO();
2581 public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2583 throw new ObjectNotFoundException("No user specified");
2584 User user = dao.getEntityById(User.class, userId);
2585 user.setAcceptedPolicy(isAccepted);
2590 public void updateAccounting(User user, Date date, long bandwidthDiff) {
2591 dao.updateAccounting(user, date, bandwidthDiff);
2595 public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2597 throw new ObjectNotFoundException("No user specified");
2598 if (folderId == null)
2599 throw new ObjectNotFoundException("No folder specified");
2600 User user = dao.getEntityById(User.class, userId);
2601 Folder folder = dao.getEntityById(Folder.class, folderId);
2602 // Check permissions
2603 if (!folder.hasReadPermission(user))
2609 public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2611 throw new ObjectNotFoundException("No user specified");
2612 User user = dao.getEntityById(User.class, userId);
2613 user.generateWebDAVPassword();
2614 return user.getWebDAVPassword();
2618 public Invitation findInvite(String code) {
2621 return dao.findInvite(code);
2625 public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2626 LDAPConnection lc = new LDAPConnection();
2627 LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2628 attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2629 attributeSet.add(new LDAPAttribute("uid", username));
2630 attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2631 attributeSet.add(new LDAPAttribute("sn", lastname));
2632 attributeSet.add(new LDAPAttribute("givenName", firstname));
2633 attributeSet.add(new LDAPAttribute("mail", email));
2634 attributeSet.add(new LDAPAttribute("userPassword", password));
2635 String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2636 LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2638 lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2639 lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2640 getConfiguration().getString("bindPassword").getBytes("UTF8"));
2642 logger.info("Successfully added LDAP account: " + dn);
2644 } catch(LDAPException e) {
2645 throw new RuntimeException(e);
2646 } catch(UnsupportedEncodingException e) {
2647 throw new RuntimeException(e);
2653 public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2654 User user = findUser(username);
2656 throw new ObjectNotFoundException("The user was not found");
2657 Invitation invite = findInvite(code);
2658 if (invite.getUser() != null)
2659 throw new InvitationUsedException("This code has already been used");
2660 invite.setUser(user);
2661 UserClass couponClass = getCouponUserClass();
2662 user.setUserClass(couponClass);
2667 public UserClass getCouponUserClass() {
2668 return dao.findCouponUserClass();