2 * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd.
4 * This file is part of GSS.
6 * GSS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GSS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GSS. If not, see <http://www.gnu.org/licenses/>.
19 package gr.ebs.gss.server.ejb;
21 import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
23 import gr.ebs.gss.admin.client.ui.UsersTable;
24 import gr.ebs.gss.client.exceptions.DuplicateNameException;
25 import gr.ebs.gss.client.exceptions.GSSIOException;
26 import gr.ebs.gss.client.exceptions.InsufficientPermissionsException;
27 import gr.ebs.gss.client.exceptions.InvitationUsedException;
28 import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
29 import gr.ebs.gss.client.exceptions.QuotaExceededException;
30 import gr.ebs.gss.server.domain.AuditInfo;
31 import gr.ebs.gss.server.domain.FileBody;
32 import gr.ebs.gss.server.domain.FileHeader;
33 import gr.ebs.gss.server.domain.FileTag;
34 import gr.ebs.gss.server.domain.FileUploadStatus;
35 import gr.ebs.gss.server.domain.Folder;
36 import gr.ebs.gss.server.domain.Group;
37 import gr.ebs.gss.server.domain.Invitation;
38 import gr.ebs.gss.server.domain.Nonce;
39 import gr.ebs.gss.server.domain.Permission;
40 import gr.ebs.gss.server.domain.User;
41 import gr.ebs.gss.server.domain.UserClass;
42 import gr.ebs.gss.server.domain.UserLogin;
43 import gr.ebs.gss.server.domain.dto.FileBodyDTO;
44 import gr.ebs.gss.server.domain.dto.FileHeaderDTO;
45 import gr.ebs.gss.server.domain.dto.FolderDTO;
46 import gr.ebs.gss.server.domain.dto.GroupDTO;
47 import gr.ebs.gss.server.domain.dto.PermissionDTO;
48 import gr.ebs.gss.server.domain.dto.StatsDTO;
49 import gr.ebs.gss.server.domain.dto.UserDTO;
52 import java.io.FileInputStream;
53 import java.io.FileNotFoundException;
54 import java.io.FileOutputStream;
55 import java.io.IOException;
56 import java.io.InputStream;
57 import java.io.UnsupportedEncodingException;
58 import java.net.MalformedURLException;
59 import java.util.ArrayList;
60 import java.util.Date;
61 import java.util.Iterator;
62 import java.util.LinkedHashSet;
63 import java.util.LinkedList;
64 import java.util.List;
65 import java.util.Locale;
66 import java.util.Random;
68 import java.util.StringTokenizer;
71 import javax.ejb.EJBException;
72 import javax.ejb.EJBTransactionRolledbackException;
73 import javax.ejb.Stateless;
74 import javax.ejb.TransactionAttribute;
75 import javax.ejb.TransactionAttributeType;
76 import javax.jms.Connection;
77 import javax.jms.ConnectionFactory;
78 import javax.jms.JMSException;
79 import javax.jms.MapMessage;
80 import javax.jms.MessageProducer;
81 import javax.jms.Queue;
82 import javax.jms.QueueConnectionFactory;
83 import javax.jms.Session;
84 import javax.naming.Context;
85 import javax.naming.InitialContext;
86 import javax.naming.NamingException;
87 import javax.persistence.PersistenceException;
89 import org.apache.commons.lang.StringUtils;
90 import org.apache.commons.logging.Log;
91 import org.apache.commons.logging.LogFactory;
92 import org.apache.solr.client.solrj.SolrQuery;
93 import org.apache.solr.client.solrj.SolrServerException;
94 import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
95 import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
96 import org.apache.solr.client.solrj.response.QueryResponse;
97 import org.apache.solr.common.SolrDocument;
98 import org.apache.solr.common.SolrDocumentList;
99 import org.apache.solr.common.SolrException;
100 import org.apache.solr.common.SolrInputDocument;
101 import org.hibernate.exception.ConstraintViolationException;
103 import com.novell.ldap.LDAPAttribute;
104 import com.novell.ldap.LDAPAttributeSet;
105 import com.novell.ldap.LDAPConnection;
106 import com.novell.ldap.LDAPEntry;
107 import com.novell.ldap.LDAPException;
110 * The concrete implementation of the ExternalAPI interface.
115 public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
117 * The default MIME type for files without an explicit one.
119 private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
122 * The size of the buffer that is used to temporarily store chunks of
123 * uploaded files, while storing them to the file repository.
125 private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
130 private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
133 * Injected reference to the GSSDAO data access facade.
140 * A cached random number generator for creating unique filenames.
142 private static Random random = new Random();
145 * Mark the folder and all of its parent folders as modified from the specified user.
147 private void touchParentFolders(Folder folder, User user, Date date) {
150 AuditInfo ai = f.getAuditInfo();
151 ai.setModifiedBy(user);
152 ai.setModificationDate(date);
158 private Long getRootFolderId(Long userId) throws ObjectNotFoundException {
160 throw new ObjectNotFoundException("No user specified");
161 return dao.getRootFolderId(userId);
165 public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
167 throw new ObjectNotFoundException("No user specified");
168 Folder folder = dao.getRootFolder(userId);
169 return folder.getDTO();
173 public FolderDTO getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
175 throw new ObjectNotFoundException("No user specified");
176 if (folderId == null)
177 throw new ObjectNotFoundException("No folder specified");
178 final User user = dao.getEntityById(User.class, userId);
179 final Folder folder = dao.getEntityById(Folder.class, folderId);
181 if (!folder.hasReadPermission(user))
182 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
183 return folder.getDTO();
187 public User getUser(Long userId) throws ObjectNotFoundException {
189 throw new ObjectNotFoundException("No user specified");
190 return dao.getEntityById(User.class, userId);
194 public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
195 return getUser(userId).getDTO();
199 public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
201 throw new ObjectNotFoundException("No group specified");
202 final Group group = dao.getEntityById(Group.class, groupId);
203 return group.getDTO();
207 public GroupDTO getGroup(Long userId, String name) throws ObjectNotFoundException {
209 throw new ObjectNotFoundException("No user specified");
211 throw new ObjectNotFoundException("No group specified");
212 User user = dao.getEntityById(User.class, userId);
213 List<Group> groups = user.getGroupsSpecified();
214 for (Group group: groups)
215 if (group.getName().equals(name))
216 return group.getDTO();
217 throw new ObjectNotFoundException("Group " + name + " not found");
221 public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
223 throw new ObjectNotFoundException("No user specified");
224 final List<Group> groups = dao.getGroups(userId);
225 final List<GroupDTO> result = new ArrayList<GroupDTO>();
226 for (final Group g : groups)
227 result.add(g.getDTO());
232 public List<FileHeaderDTO> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
233 throws ObjectNotFoundException, InsufficientPermissionsException {
236 throw new ObjectNotFoundException("No user specified");
237 if (folderId == null)
238 throw new ObjectNotFoundException("No folder specified");
239 User user = dao.getEntityById(User.class, userId);
240 Folder folder = dao.getEntityById(Folder.class, folderId);
241 if (!folder.hasReadPermission(user))
242 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
243 // Do the actual work.
244 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
245 List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
246 for (FileHeader f : files)
247 result.add(f.getDTO());
252 public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
255 throw new ObjectNotFoundException("No user specified");
257 throw new ObjectNotFoundException("No group specified");
259 // Do the actual work.
260 final List<User> users = dao.getUsers(groupId);
261 final List<UserDTO> result = new ArrayList<UserDTO>();
262 for (final User u : users)
263 result.add(u.getDTO());
268 public FolderDTO createFolder(Long userId, Long parentId, String name)
269 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
272 throw new ObjectNotFoundException("No user specified");
273 if (StringUtils.isEmpty(name))
274 throw new ObjectNotFoundException("New folder name is empty");
275 if (parentId == null)
276 throw new ObjectNotFoundException("No parent specified");
277 if (dao.existsFolderOrFile(parentId, name))
278 throw new DuplicateNameException("A folder or file with the name '" +
279 name + "' already exists at this level");
281 User creator = dao.getEntityById(User.class, userId);
283 Folder parent = null;
285 parent = dao.getEntityById(Folder.class, parentId);
286 } catch (ObjectNotFoundException onfe) {
287 // Supply a more accurate problem description.
288 throw new ObjectNotFoundException("Parent folder not found");
290 if (!parent.hasWritePermission(creator))
291 throw new InsufficientPermissionsException("You don't have the permissions" +
292 " to write to this folder");
294 // Do the actual work.
295 return createFolder(name, parent, creator);
299 * Create a new folder with the provided name, parent and owner.
304 * @return the new folder
306 private FolderDTO createFolder(String name, Folder parent, User creator) {
307 Folder folder = new Folder();
308 folder.setName(name);
309 if (parent != null) {
310 parent.addSubfolder(folder);
311 folder.setOwner(parent.getOwner());
313 folder.setOwner(creator);
315 Date now = new Date();
316 AuditInfo auditInfo = new AuditInfo();
317 auditInfo.setCreatedBy(creator);
318 auditInfo.setCreationDate(now);
319 auditInfo.setModifiedBy(creator);
320 auditInfo.setModificationDate(now);
321 folder.setAuditInfo(auditInfo);
322 touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
325 for (Permission p : parent.getPermissions()) {
326 Permission permission = new Permission();
327 permission.setGroup(p.getGroup());
328 permission.setUser(p.getUser());
329 permission.setRead(p.getRead());
330 permission.setWrite(p.getWrite());
331 permission.setModifyACL(p.getModifyACL());
332 folder.addPermission(permission);
335 Permission permission = new Permission();
336 permission.setUser(creator);
337 permission.setRead(true);
338 permission.setWrite(true);
339 permission.setModifyACL(true);
340 folder.addPermission(permission);
344 folder.setReadForAll(parent.isReadForAll());
347 return folder.getDTO();
351 public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
354 throw new ObjectNotFoundException("No user specified");
355 if (folderId == null)
356 throw new ObjectNotFoundException("No folder specified");
358 // Do the actual work.
359 final Folder folder = dao.getEntityById(Folder.class, folderId);
360 final Folder parent = folder.getParent();
362 throw new ObjectNotFoundException("Deleting the root folder is not allowed");
363 final User user = dao.getEntityById(User.class, userId);
364 if (!folder.hasDeletePermission(user)) {
365 logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
366 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
368 removeSubfolderFiles(folder);
369 parent.removeSubfolder(folder);
371 touchParentFolders(parent, user, new Date());
375 * Traverses the folder and deletes all actual files (file system)
376 * regardless of permissions
380 private void removeSubfolderFiles(Folder folder) {
381 //remove files for all subfolders
382 for (Folder subfolder:folder.getSubfolders())
383 removeSubfolderFiles(subfolder);
384 //remove this folder's file bodies (actual files)
385 for (FileHeader file:folder.getFiles()) {
386 for (FileBody body:file.getBodies())
387 deleteActualFile(body.getStoredFilePath());
388 indexFile(file.getId(), true);
393 @SuppressWarnings("unchecked")
394 public List<FolderDTO> getSubfolders(Long userId, Long folderId)
395 throws ObjectNotFoundException, InsufficientPermissionsException {
397 throw new ObjectNotFoundException("No user specified");
398 if (folderId == null)
399 throw new ObjectNotFoundException("No folder specified");
400 User user = dao.getEntityById(User.class, userId);
401 Folder folder = dao.getEntityById(Folder.class, folderId);
402 if (!folder.hasReadPermission(user))
403 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
404 List<FolderDTO> result = new ArrayList<FolderDTO>();
405 if (folder.hasReadPermission(user))
406 for (Folder f : folder.getSubfolders())
407 if (f.hasReadPermission(user) && !f.isDeleted())
408 result.add(f.getDTO());
413 public FolderDTO updateFolder(Long userId, Long folderId, String folderName,
415 Set<PermissionDTO> permissions)
416 throws InsufficientPermissionsException, ObjectNotFoundException,
417 DuplicateNameException {
421 throw new ObjectNotFoundException("No user specified");
422 if (folderId == null)
423 throw new ObjectNotFoundException("No folder specified");
425 Folder folder = dao.getEntityById(Folder.class, folderId);
426 User user = dao.getEntityById(User.class, userId);
427 if (folderName != null && !folder.hasWritePermission(user))
428 throw new InsufficientPermissionsException("You don't have the necessary permissions");
429 if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
430 throw new InsufficientPermissionsException("You don't have the necessary permissions");
431 // Check permissions for making file public.
432 if (readForAll != null && !user.equals(folder.getOwner()))
433 throw new InsufficientPermissionsException("Only the owner can make a folder public or not public");
435 Folder parent = folder.getParent();
436 if (folderName != null) {
438 if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
439 throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
441 // Do the actual modification.
442 folder.setName(folderName);
444 if (permissions != null)
445 setFolderPermissions(user, folder, permissions);
446 if (readForAll != null)
447 setFolderReadForAll(user, folder, readForAll);
448 folder.getAuditInfo().setModificationDate(new Date());
449 folder.getAuditInfo().setModifiedBy(user);
451 touchParentFolders(folder, user, new Date());
452 // Re-index the folder contents if it was modified.
453 if ((permissions != null && !permissions.isEmpty()) || readForAll != null) {
457 return folder.getDTO();
460 private void indexFolder(Folder folder) {
461 for (FileHeader fh : folder.getFiles())
462 indexFile(fh.getId(), false);
463 for (Folder f : folder.getSubfolders())
468 public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
471 throw new ObjectNotFoundException("No user specified");
472 if (StringUtils.isEmpty(name))
473 throw new ObjectNotFoundException("New group name is empty");
474 if (name.indexOf('/')>=0)
475 throw new IllegalArgumentException("Character '/' is not allowed in group name");
476 if (dao.existsGroup(userId, name))
477 throw new DuplicateNameException("A group with the name '" + name + "' already exists");
479 // TODO: Check permissions
481 final User owner = dao.getEntityById(User.class, userId);
483 // Do the actual work.
484 owner.createGroup(name);
488 public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
491 throw new ObjectNotFoundException("No user specified");
493 throw new ObjectNotFoundException("No group specified");
495 // Do the actual work.
496 final User owner = dao.getEntityById(User.class, userId);
497 final Group group = dao.getEntityById(Group.class, groupId);
498 final Date now = new Date();
499 // Only delete the group if actually owned by the user.
500 if (group.getOwner().equals(owner)) {
501 List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
502 for (Folder f : folders){
503 f.getPermissions().removeAll(group.getPermissions());
504 touchFolder(f, owner, now);
505 for(FileHeader file : f.getFiles()){
506 file.getPermissions().removeAll(group.getPermissions());
507 touchFile(file, owner, now);
510 List<FileHeader> files = dao.getFilesPermittedForGroup(userId, groupId);
511 for(FileHeader h : files){
512 h.getPermissions().removeAll(group.getPermissions());
513 touchFile(h, owner, now);
515 owner.removeSpecifiedGroup(group);
518 else throw new InsufficientPermissionsException("You are not the owner of this group");
522 public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
523 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
524 InsufficientPermissionsException, QuotaExceededException {
527 file = uploadFile(stream, userId);
528 } catch ( IOException ioe) {
529 // Supply a more accurate problem description.
530 throw new GSSIOException("Problem creating file",ioe);
532 return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
536 * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
539 public void indexFile(Long fileId, boolean delete) {
540 Connection qConn = null;
541 Session session = null;
542 MessageProducer sender = null;
544 Context jndiCtx = new InitialContext();
545 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
546 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
547 qConn = factory.createConnection();
548 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
549 sender = session.createProducer(queue);
551 MapMessage map = session.createMapMessage();
552 map.setObject("id", fileId);
553 map.setBoolean("delete", delete);
556 catch (NamingException e) {
557 logger.error("Index was not updated: ", e);
559 catch (JMSException e) {
560 logger.error("Index was not updated: ", e);
571 catch (JMSException e) {
580 * A helper method that generates a unique file path for a stored file. The
581 * files are stored using random hash names that are distributed evenly in
582 * a 2-level tree of subdirectories named after the first two hex characters
583 * in the name. For example, file ab1234cd5769f will be stored in the path
584 * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
585 * if they don't already exist.
587 * @return a unique new file path
589 private String generateRepositoryFilePath() {
590 String filename = Long.toHexString(random.nextLong());
591 String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
592 File root = new File(fileRepositoryPath);
595 File firstFolder = new File(root + File.separator + filename.substring(0, 1));
596 if (!firstFolder.exists())
598 File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
599 if (!secondFolder.exists())
600 secondFolder.mkdir();
601 return secondFolder + File.separator + filename;
605 public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
608 throw new ObjectNotFoundException("No user specified");
610 throw new ObjectNotFoundException("No file specified");
612 // Do the actual work.
613 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
614 final Folder parent = file.getFolder();
616 throw new ObjectNotFoundException("The specified file has no parent folder");
617 final User user = dao.getEntityById(User.class, userId);
618 if (!file.hasDeletePermission(user))
619 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
620 for (final FileBody body : file.getBodies())
621 deleteActualFile(body.getStoredFilePath());
623 touchParentFolders(parent, user, new Date());
624 indexFile(fileId, true);
628 public void deleteActualFile(String path) {
631 File file = new File(path);
633 logger.error("Could not delete file " + path);
637 public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
639 throw new ObjectNotFoundException("No user specified");
640 if (fileHeaderId == null)
641 throw new ObjectNotFoundException("No file specified");
642 if (StringUtils.isEmpty(tag))
643 throw new ObjectNotFoundException("Tag is empty");
645 final User user = dao.getEntityById(User.class, userId);
646 final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
647 final Folder parent = fh.getFolder();
649 throw new ObjectNotFoundException("The specified file has no parent folder");
650 user.addTag(fh, tag);
651 touchParentFolders(parent, user, new Date());
655 public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
656 return dao.getUserTags(userId);
660 public void updateFile(Long userId, Long fileId, String name,
661 String tagSet, Date modificationDate, Boolean versioned,
662 Boolean readForAll, Set<PermissionDTO> permissions)
663 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
665 throw new ObjectNotFoundException("No user specified");
667 throw new ObjectNotFoundException("No file specified");
668 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
669 final Folder parent = file.getFolder();
671 throw new ObjectNotFoundException("The specified file has no parent folder");
673 User user = dao.getEntityById(User.class, userId);
674 // Check permissions for modifying the file metadata.
675 if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
676 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
677 // Check permissions for making file public.
678 if (readForAll != null && !user.equals(file.getOwner()))
679 throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
680 // Check permissions for modifying the ACL.
681 if(permissions != null && !permissions.isEmpty() && !file.hasModifyACLPermission(user))
682 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update the permissions on file " + file.getName() + "(" + file.getId() + ")");
685 // Do plain check for file already exists.
686 // Extreme concurrency case should be caught by constraint violation later.
687 if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
691 if (modificationDate != null)
692 file.getAuditInfo().setModificationDate(modificationDate);
694 file.getAuditInfo().setModificationDate(new Date());
695 file.getAuditInfo().setModifiedBy(user);
697 List<FileTag> tags = file.getFileTags();
698 if (tagSet != null) {
699 Iterator<FileTag> i = tags.iterator();
700 while (i.hasNext()) {
701 FileTag tag = i.next();
708 StringTokenizer st = new StringTokenizer(tagSet, ",");
709 while (st.hasMoreTokens())
710 new FileTag(user, file, st.nextToken().trim());
712 if (versioned != null && !file.isVersioned() == versioned) {
713 if (file.isVersioned())
714 removeOldVersions(userId, fileId);
715 file.setVersioned(versioned);
717 if (readForAll != null && user.equals(file.getOwner()))
718 file.setReadForAll(readForAll);
719 if (permissions != null && !permissions.isEmpty())
720 setFilePermissions(file, permissions);
723 * Force constraint violation to manifest itself here.
724 * This should cover extreme concurrency cases that the simple check
725 * above hasn't caught.
730 catch (EJBTransactionRolledbackException e) {
731 Throwable cause = e.getCause();
732 if (cause instanceof PersistenceException && cause.getCause() instanceof ConstraintViolationException)
733 throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
737 touchParentFolders(parent, user, new Date());
739 // Re-index the file if it was modified.
740 if (name != null || tagSet != null || (permissions != null && !permissions.isEmpty()) || readForAll != null)
741 indexFile(fileId, false);
745 public InputStream getFileContents(Long userId, Long fileId)
746 throws ObjectNotFoundException, InsufficientPermissionsException {
748 throw new ObjectNotFoundException("No user specified");
750 throw new ObjectNotFoundException("No file specified");
752 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
753 User user = dao.getEntityById(User.class, userId);
754 if (!header.hasReadPermission(user)) {
755 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
756 throw new InsufficientPermissionsException("You don't have the necessary permissions");
759 File f = new File(header.getCurrentBody().getStoredFilePath());
761 return new FileInputStream(f);
762 } catch (FileNotFoundException e) {
763 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
764 throw new ObjectNotFoundException("The file contents could not be located");
769 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
772 public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
774 throw new ObjectNotFoundException("No user specified");
776 throw new ObjectNotFoundException("No file specified");
778 throw new ObjectNotFoundException("No file specified");
780 final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
781 final FileBody body = dao.getEntityById(FileBody.class, bodyId);
782 final User user = dao.getEntityById(User.class, userId);
783 if (!header.hasReadPermission(user)) {
784 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
785 throw new InsufficientPermissionsException("You don't have the necessary permissions");
788 File f = new File(body.getStoredFilePath());
790 return new FileInputStream(f);
791 } catch (FileNotFoundException e) {
792 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
793 throw new ObjectNotFoundException("The file contents could not be located");
798 public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
800 throw new ObjectNotFoundException("No user specified");
802 throw new ObjectNotFoundException("No file specified");
803 final User user = dao.getEntityById(User.class, userId);
804 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
805 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
806 throw new InsufficientPermissionsException("You don't have the necessary permissions");
807 return file.getDTO();
811 public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
813 throw new ObjectNotFoundException("No user specified");
815 throw new ObjectNotFoundException("No file specified");
816 User user = dao.getEntityById(User.class, userId);
817 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
818 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
819 throw new InsufficientPermissionsException("You don't have the necessary permissions");
820 FileBody body = dao.getEntityById(FileBody.class, bodyId);
821 return body.getDTO();
825 public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
826 throws ObjectNotFoundException {
828 throw new ObjectNotFoundException("No user specified");
829 if (StringUtils.isEmpty(path))
830 throw new ObjectNotFoundException("No path specified");
832 User owner = dao.getEntityById(User.class, ownerId);
833 List<String> pathElements = new ArrayList<String>();
834 StringTokenizer st = new StringTokenizer(path, "/");
835 while (st.hasMoreTokens())
836 pathElements.add(st.nextToken());
837 if (pathElements.size() < 1)
838 return getRootFolder(owner.getId());
839 // Store the last element, since it requires special handling.
840 String lastElement = pathElements.remove(pathElements.size() - 1);
842 Folder cursor = null;
843 Long rootFolderId = getRootFolderId(owner.getId());
844 // Traverse and verify the specified folder path.
845 for (String pathElement : pathElements) {
846 cursor = getFolder(cursor==null ? rootFolderId : cursor.getId(), pathElement);
847 if (cursor.isDeleted())
848 throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
851 // Use the lastElement to retrieve the actual resource.
852 Object resource = null;
854 FileHeaderDTO file = getFile(cursor==null ? rootFolderId : cursor.getId(), lastElement);
855 if (ignoreDeleted && file.isDeleted())
856 throw new ObjectNotFoundException("Resource not found");
858 } catch (ObjectNotFoundException e) {
859 // Perhaps the requested resource is not a file, so
860 // check for folders as well.
861 FolderDTO folder = getFolder(cursor==null ? rootFolderId : cursor.getId(), lastElement).getDTO();
862 if (ignoreDeleted && folder.isDeleted())
863 throw new ObjectNotFoundException("Resource not found");
870 * Retrieve a file for the specified user that has the specified name and
871 * its parent folder has id equal to folderId.
873 * @param folderId the ID of the parent folder
874 * @param name the name of the requested file
875 * @return the file found
876 * @throws ObjectNotFoundException if the specified folder or file was not
877 * found, with the exception message mentioning the precise
880 private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
881 if (folderId == null)
882 throw new ObjectNotFoundException("No parent folder specified");
883 if (StringUtils.isEmpty(name))
884 throw new ObjectNotFoundException("No file specified");
886 FileHeader file = dao.getFile(folderId, name);
887 return file.getDTO();
891 * Retrieve a folder for the specified user that has the specified name and
892 * its parent folder has id equal to parentId.
894 * @param parentId the ID of the parent folder
895 * @param name the name of the requested folder
896 * @return the folder found
897 * @throws ObjectNotFoundException if the specified folder or parent was not
898 * found, with the exception message mentioning the precise
901 private Folder getFolder(Long parentId, String name) throws ObjectNotFoundException {
902 if (parentId == null)
903 throw new ObjectNotFoundException("No parent folder specified");
904 if (StringUtils.isEmpty(name))
905 throw new ObjectNotFoundException("No folder specified");
907 Folder folder = dao.getFolder(parentId, name);
911 private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
914 file = uploadFile(resourceInputStream, userId);
915 } catch ( IOException ioe) {
916 // Supply a more accurate problem description.
917 throw new GSSIOException("Problem creating file",ioe);
919 return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
923 public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
925 throw new ObjectNotFoundException("No user specified");
927 throw new ObjectNotFoundException("No file specified");
928 if (StringUtils.isEmpty(dest))
929 throw new ObjectNotFoundException("No destination specified");
931 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
932 if (!(destination instanceof FolderDTO))
933 throw new ObjectNotFoundException("Destination parent folder not found");
934 FolderDTO parent = (FolderDTO) destination;
935 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
939 public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
941 throw new ObjectNotFoundException("No user specified");
943 throw new ObjectNotFoundException("No owner specified");
945 throw new ObjectNotFoundException("No file specified");
946 if (StringUtils.isEmpty(dest))
947 throw new ObjectNotFoundException("No destination specified");
949 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
950 if (!(destination instanceof FolderDTO))
951 throw new ObjectNotFoundException("Destination parent folder not found");
952 FolderDTO parent = (FolderDTO) destination;
953 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
957 public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
959 throw new ObjectNotFoundException("No user specified");
961 throw new ObjectNotFoundException("No file specified");
963 throw new ObjectNotFoundException("No destination specified");
964 if (StringUtils.isEmpty(destName))
965 throw new ObjectNotFoundException("No destination file name specified");
967 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
968 Folder destination = dao.getEntityById(Folder.class, destId);
969 User user = dao.getEntityById(User.class, userId);
970 if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
971 throw new InsufficientPermissionsException("You don't have the necessary permissions");
972 boolean versioned = file.isVersioned();
973 int versionsNumber = file.getBodies().size();
974 FileBody oldestBody = file.getBodies().get(0);
975 assert oldestBody != null;
976 File contents = new File(oldestBody.getStoredFilePath());
978 createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
979 FileHeader copiedFile = dao.getFile(destination.getId(), destName);
980 copiedFile.setVersioned(versioned);
982 if (versionsNumber > 1)
983 for (int i = 1; i < versionsNumber; i++) {
984 FileBody body = file.getBodies().get(i);
986 contents = new File(body.getStoredFilePath());
987 updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
989 List<FileTag> tags = file.getFileTags();
990 for (FileTag tag : tags)
991 createTag(userId, copiedFile.getId(), tag.getTag());
993 } catch (FileNotFoundException e) {
994 throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
1000 public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1002 throw new ObjectNotFoundException("No user specified");
1003 if (folderId == null)
1004 throw new ObjectNotFoundException("No folder specified");
1005 if (StringUtils.isEmpty(dest))
1006 throw new ObjectNotFoundException("No destination specified");
1008 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
1009 if (!(destination instanceof FolderDTO))
1010 throw new ObjectNotFoundException("Destination folder not found");
1011 FolderDTO parent = (FolderDTO) destination;
1012 copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
1016 public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1018 throw new ObjectNotFoundException("No user specified");
1019 if (folderId == null)
1020 throw new ObjectNotFoundException("No folder specified");
1022 throw new ObjectNotFoundException("No destination specified");
1023 if (StringUtils.isEmpty(destName))
1024 throw new ObjectNotFoundException("No destination folder name specified");
1025 Folder folder = dao.getEntityById(Folder.class, folderId);
1026 Folder destination = dao.getEntityById(Folder.class, destId);
1027 User user = dao.getEntityById(User.class, userId);
1028 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1029 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1030 createFolder(user.getId(), destination.getId(), destName);
1034 public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1036 throw new ObjectNotFoundException("No user specified");
1037 if (ownerId == null)
1038 throw new ObjectNotFoundException("No owner specified");
1039 if (folderId == null)
1040 throw new ObjectNotFoundException("No folder specified");
1041 if (StringUtils.isEmpty(dest))
1042 throw new ObjectNotFoundException("No destination specified");
1044 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1045 if (!(destination instanceof FolderDTO))
1046 throw new ObjectNotFoundException("Destination folder not found");
1047 FolderDTO parent = (FolderDTO) destination;
1048 copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1052 public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1054 throw new ObjectNotFoundException("No user specified");
1055 if (folderId == null)
1056 throw new ObjectNotFoundException("No folder specified");
1058 throw new ObjectNotFoundException("No destination specified");
1059 if (StringUtils.isEmpty(destName))
1060 throw new ObjectNotFoundException("No destination folder name specified");
1062 Folder folder = dao.getEntityById(Folder.class, folderId);
1063 Folder destination = dao.getEntityById(Folder.class, destId);
1064 final User user = dao.getEntityById(User.class, userId);
1065 // XXX: quick fix need to copy only visible items to user (Source
1067 if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1069 if(folder.isDeleted())//do not copy trashed folder and contents
1071 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1072 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1073 createFolder(user.getId(), destination.getId(), destName);
1074 Folder createdFolder = dao.getFolder(destination.getId(), destName);
1075 List<FileHeader> files = folder.getFiles();
1077 for (FileHeader file : files)
1078 if(!file.isDeleted())
1079 copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1080 List<Folder> subFolders = folder.getSubfolders();
1081 if (subFolders != null)
1082 for (Folder sub : subFolders)
1083 if(!sub.getId().equals(createdFolder.getId()))
1084 copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1089 * For a provided path, remove the last element and return the rest, that is
1090 * the path of the parent folder.
1092 * @param path the specified path
1093 * @return the path of the parent folder
1094 * @throws ObjectNotFoundException if the provided string contains no path
1097 private String getParentPath(String path) throws ObjectNotFoundException {
1098 int lastDelimiter = path.lastIndexOf('/');
1099 if (lastDelimiter == 0)
1101 if (lastDelimiter == -1)
1103 throw new ObjectNotFoundException("There is no parent in the path: " + path);
1104 else if (lastDelimiter < path.length() - 1)
1105 // Return the part before the delimiter.
1106 return path.substring(0, lastDelimiter);
1108 // Remove the trailing delimiter and then recurse.
1109 String strippedTrail = path.substring(0, lastDelimiter);
1110 return getParentPath(strippedTrail);
1115 * Get the last element in a path that denotes the file or folder name.
1117 * @param path the provided path
1118 * @return the last element in the path
1120 private String getLastElement(String path) {
1121 int lastDelimiter = path.lastIndexOf('/');
1122 if (lastDelimiter == -1)
1125 else if (lastDelimiter < path.length() - 1)
1126 // Return the part after the delimiter.
1127 return path.substring(lastDelimiter + 1);
1129 // Remove the trailing delimiter and then recurse.
1130 String strippedTrail = path.substring(0, lastDelimiter);
1131 return getLastElement(strippedTrail);
1136 public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1138 throw new ObjectNotFoundException("No user specified");
1140 throw new ObjectNotFoundException("No file specified");
1142 // Do the actual work.
1143 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1144 Folder parent = file.getFolder();
1146 throw new ObjectNotFoundException("The specified file has no parent folder");
1147 User user = dao.getEntityById(User.class, userId);
1148 trashFile(user, file);
1149 touchParentFolders(parent, user, new Date());
1152 private void trashFile(User user, FileHeader file) throws InsufficientPermissionsException {
1153 if (!file.hasDeletePermission(user))
1154 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1156 file.setDeleted(true);
1160 public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1162 throw new ObjectNotFoundException("No user specified");
1163 if (ownerId == null)
1164 throw new ObjectNotFoundException("No owner specified");
1166 throw new ObjectNotFoundException("No file specified");
1167 if (StringUtils.isEmpty(dest))
1168 throw new ObjectNotFoundException("No destination specified");
1170 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1171 if (!(destination instanceof FolderDTO))
1172 throw new ObjectNotFoundException("Destination parent folder not found");
1173 FolderDTO parent = (FolderDTO) destination;
1174 moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1178 public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1180 throw new ObjectNotFoundException("No user specified");
1182 throw new ObjectNotFoundException("No file specified");
1184 throw new ObjectNotFoundException("No destination specified");
1185 if (StringUtils.isEmpty(destName))
1186 throw new ObjectNotFoundException("No destination file name specified");
1188 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1189 Folder source = file.getFolder();
1190 Folder destination = dao.getEntityById(Folder.class, destId);
1192 User owner = dao.getEntityById(User.class, userId);
1193 if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1194 throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1196 // if the destination folder belongs to another user:
1197 if (!file.getOwner().equals(destination.getOwner())) {
1198 // (a) check if the destination quota allows the move
1199 if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1200 throw new QuotaExceededException("Not enough free space available");
1201 User newOwner = destination.getOwner();
1202 // (b) if quota OK, change the owner of the file
1203 file.setOwner(newOwner);
1204 // if the file has no permission for the new owner, add it
1205 Permission ownerPermission = null;
1206 for (final Permission p : file.getPermissions())
1207 if (p.getUser() != null)
1208 if (p.getUser().equals(newOwner)) {
1209 ownerPermission = p;
1212 if (ownerPermission == null) {
1213 ownerPermission = new Permission();
1214 ownerPermission.setUser(newOwner);
1215 file.addPermission(ownerPermission);
1217 ownerPermission.setRead(true);
1218 ownerPermission.setWrite(true);
1219 ownerPermission.setModifyACL(true);
1221 // move the file to the destination folder
1222 file.setFolder(destination);
1223 touchParentFolders(source, owner, new Date());
1224 touchParentFolders(destination, owner, new Date());
1228 public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1230 throw new ObjectNotFoundException("No user specified");
1231 if (ownerId == null)
1232 throw new ObjectNotFoundException("No owner specified");
1233 if (folderId == null)
1234 throw new ObjectNotFoundException("No folder specified");
1235 if (StringUtils.isEmpty(dest))
1236 throw new ObjectNotFoundException("No destination specified");
1238 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1239 if (!(destination instanceof FolderDTO))
1240 throw new ObjectNotFoundException("Destination parent folder not found");
1241 FolderDTO parent = (FolderDTO) destination;
1242 moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1246 public void moveFolder(Long userId, Long folderId, Long destId, String destName)
1247 throws ObjectNotFoundException, InsufficientPermissionsException,
1248 QuotaExceededException {
1249 Folder source = dao.getEntityById(Folder.class, folderId);
1250 Folder destination = dao.getEntityById(Folder.class, destId);
1251 User user = dao.getEntityById(User.class, userId);
1252 User sourceOwner = source.getOwner();
1253 User destinationOwner = destination.getOwner();
1254 // Do not move trashed folders and contents.
1255 if (source.isDeleted())
1257 // Check permissions.
1258 if (!destination.hasWritePermission(user)
1259 || !source.hasReadPermission(user)
1260 || !source.hasWritePermission(user))
1261 throw new InsufficientPermissionsException("You don't have the " +
1262 "necessary permissions");
1263 // Use the same timestamp for all subsequent modifications to make
1264 // changes appear simultaneous.
1265 Date now = new Date();
1266 // If source and destination are not in the same user's namespace,
1267 // change owners and check quota.
1268 if (!sourceOwner.equals(destinationOwner)) {
1269 changeOwner(source, destinationOwner, user, now);
1270 if (getQuotaLeft(destinationOwner.getId()) < 0)
1271 throw new QuotaExceededException("Not enough free space " +
1272 "available in destination folder");
1274 // Perform the move.
1275 Folder oldParent = source.getParent();
1276 oldParent.removeSubfolder(source);
1277 destination.addSubfolder(source);
1278 // Mark the former parent and destination trees upwards as modified.
1279 touchParentFolders(oldParent, user, now);
1280 touchParentFolders(source, user, now);
1284 * Recursively change the owner of the specified folder and all of its
1285 * contents to the specified owner. Also mark them all as modified with the
1286 * specified modifier and modificationDate.
1288 private void changeOwner(Folder folder, User owner, User modifier, Date modificationDate) {
1289 for (FileHeader file: folder.getFiles()) {
1290 file.setOwner(owner);
1291 file.getAuditInfo().setModificationDate(modificationDate);
1292 file.getAuditInfo().setModifiedBy(modifier);
1294 for (Folder sub: folder.getSubfolders())
1295 changeOwner(sub, owner, modifier, modificationDate);
1296 folder.setOwner(owner);
1297 folder.getAuditInfo().setModificationDate(modificationDate);
1298 folder.getAuditInfo().setModifiedBy(modifier);
1302 public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1305 throw new ObjectNotFoundException("No user specified");
1307 // Do the actual work.
1308 final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1309 final List<FileHeader> files = dao.getDeletedFiles(userId);
1310 for (final FileHeader f : files)
1311 result.add(f.getDTO());
1316 public void removeFileFromTrash(Long userId, Long fileId)
1317 throws ObjectNotFoundException, InsufficientPermissionsException {
1319 throw new ObjectNotFoundException("No user specified");
1321 throw new ObjectNotFoundException("No file specified");
1323 // Do the actual work.
1324 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1325 Folder parent = file.getFolder();
1327 throw new ObjectNotFoundException("The specified file has no parent folder");
1328 User user = dao.getEntityById(User.class, userId);
1329 untrashFile(user, file);
1330 touchParentFolders(parent, user, new Date());
1333 private void untrashFile(User user, FileHeader file) throws InsufficientPermissionsException {
1334 if (!file.hasDeletePermission(user))
1335 throw new InsufficientPermissionsException("User " + user.getUsername() +
1336 " cannot restore file " + file.getName());
1338 file.setDeleted(false);
1342 public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1344 throw new ObjectNotFoundException("No user specified");
1345 if (folderId == null)
1346 throw new ObjectNotFoundException("No folder specified");
1347 Folder folder = dao.getEntityById(Folder.class, folderId);
1348 User user = dao.getEntityById(User.class, userId);
1349 trashFolder(user, folder);
1350 touchParentFolders(folder, user, new Date());
1353 private void trashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException {
1354 if (!folder.hasDeletePermission(user))
1355 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1356 folder.setDeleted(true);
1357 for (FileHeader file : folder.getFiles())
1358 trashFile(user, file);
1359 for (Folder subFolder : folder.getSubfolders())
1360 trashFolder(user, subFolder);
1364 public void removeFolderFromTrash(Long userId, Long folderId)
1365 throws ObjectNotFoundException, InsufficientPermissionsException {
1367 throw new ObjectNotFoundException("No user specified");
1368 if (folderId == null)
1369 throw new ObjectNotFoundException("No folder specified");
1370 Folder folder = dao.getEntityById(Folder.class, folderId);
1371 User user = dao.getEntityById(User.class, userId);
1372 untrashFolder(user, folder);
1373 touchParentFolders(folder, user, new Date());
1376 private void untrashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException {
1377 if (!folder.hasDeletePermission(user))
1378 throw new InsufficientPermissionsException("User " + user.getUsername() +
1379 " cannot restore folder " + folder.getName());
1380 folder.setDeleted(false);
1381 for (FileHeader file : folder.getFiles())
1382 untrashFile(user, file);
1383 for (Folder subFolder : folder.getSubfolders())
1384 untrashFolder(user, subFolder);
1388 public List<FolderDTO> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1389 List<Folder> folders = dao.getDeletedRootFolders(userId);
1390 List<FolderDTO> result = new ArrayList<FolderDTO>();
1391 for (Folder folder : folders)
1392 result.add(folder.getDTO());
1397 public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1398 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1399 for (FolderDTO fdto : deletedRootFolders)
1400 deleteFolder(userId, fdto.getId());
1401 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1402 for (FileHeaderDTO filedto : deletedFiles)
1403 deleteFile(userId, filedto.getId());
1407 public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1408 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1409 for (FolderDTO fdto : deletedRootFolders)
1410 removeFolderFromTrash(userId, fdto.getId());
1411 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1412 for (FileHeaderDTO filedto : deletedFiles)
1413 removeFileFromTrash(userId, filedto.getId());
1417 public User createUser(String username, String name, String mail,
1418 String idp, String idpid) throws ObjectNotFoundException {
1419 if (username == null)
1420 throw new ObjectNotFoundException("No username specified");
1422 throw new ObjectNotFoundException("No name specified");
1424 User user = new User();
1425 user.setUsername(username);
1427 user.setEmail(mail);
1428 user.setIdentityProvider(idp);
1429 user.setIdentityProviderId(idpid);
1430 Date now = new Date();
1431 AuditInfo auditInfo = new AuditInfo();
1432 auditInfo.setCreationDate(now);
1433 auditInfo.setModificationDate(now);
1434 user.setAuditInfo(auditInfo);
1435 user.setActive(true);
1436 user.generateAuthToken();
1437 user.generateWebDAVPassword();
1438 user.setUserClass(getDefaultUserClass());
1440 // Make sure we get an ID in the user object.
1442 // Create the root folder for the user.
1443 createFolder(user.getName(), null, user);
1448 * Get the default user class, which is the one with the lowest quota.
1450 private UserClass getDefaultUserClass() {
1451 return getUserClasses().get(0);
1455 public List<UserClass> getUserClasses() {
1456 List<UserClass> classes = dao.getUserClasses();
1457 // Create a default user class for first-time use. Afterwards, the
1458 // admin should modify or add to the userclass table.
1459 if (classes.size() == 0) {
1460 UserClass defaultClass = new UserClass();
1461 defaultClass.setName("default");
1462 Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L));
1463 defaultClass.setQuota(defaultQuota);
1464 dao.create(defaultClass);
1465 classes.add(defaultClass);
1471 public User findUserByEmail(String email) {
1472 return dao.findUserByEmail(email);
1476 public void updateUser(User user) {
1481 public User findUser(String username) {
1482 if (username == null)
1484 return dao.findUser(username);
1488 public User updateUserToken(Long userId) throws ObjectNotFoundException {
1490 throw new ObjectNotFoundException("No user specified");
1491 User user = dao.getEntityById(User.class, userId);
1492 user.generateAuthToken();
1497 public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1499 throw new ObjectNotFoundException("No user specified");
1500 if (folderId == null)
1501 throw new ObjectNotFoundException("No folder specified");
1502 User user = dao.getEntityById(User.class, userId);
1503 Folder folder = dao.getEntityById(Folder.class, folderId);
1504 if(!folder.hasReadPermission(user))
1505 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1506 Set<Permission> perms = folder.getPermissions();
1507 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1508 for (Permission perm : perms)
1509 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1510 result.add(perm.getDTO());
1511 for (Permission perm : perms)
1512 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1514 result.add(perm.getDTO());
1520 * Set the provided permissions as the new permissions of the specified
1525 * @param permissions
1526 * @throws ObjectNotFoundException
1527 * @throws InsufficientPermissionsException
1529 private void setFolderPermissions(User user, Folder folder, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1530 if (permissions != null && !permissions.isEmpty()) {
1531 User owner = folder.getOwner();
1532 PermissionDTO ownerPerm = null;
1533 for (PermissionDTO dto : permissions)
1534 if (dto.getUser() != null && dto.getUser().getId().equals(owner.getId())) {
1538 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1539 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1540 // Delete previous entries
1541 for (Permission perm: folder.getPermissions())
1543 folder.getPermissions().clear();
1544 for (PermissionDTO dto : permissions) {
1545 // Skip 'empty' permission entries.
1546 if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1547 folder.addPermission(getPermission(dto));
1550 for (FileHeader file : folder.getFiles()) {
1551 setFilePermissions(file, permissions);
1552 Date now = new Date();
1553 file.getAuditInfo().setModificationDate(now);
1554 file.getAuditInfo().setModifiedBy(user);
1556 for (Folder sub : folder.getSubfolders())
1557 setFolderPermissions(user, sub, permissions);
1561 private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1562 Permission res = new Permission();
1563 if (dto.getGroup() != null)
1564 res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1565 else if (dto.getUser() != null)
1566 if (dto.getUser().getId() == null)
1567 res.setUser(dao.getUser(dto.getUser().getUsername()));
1569 res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1570 res.setRead(dto.hasRead());
1571 res.setWrite(dto.hasWrite());
1572 res.setModifyACL(dto.hasModifyACL());
1577 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1580 public List<UserDTO> getUsersByUserNameLike(String username) {
1581 List<User> users = dao.getUsersByUserNameLike(username);
1582 List<UserDTO> result = new ArrayList<UserDTO>();
1583 for (User u : users)
1584 result.add(u.getDTO());
1590 public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1592 throw new ObjectNotFoundException("No user specified");
1593 if (groupId == null)
1594 throw new ObjectNotFoundException("No group specified");
1595 if (userToAddId == null)
1596 throw new ObjectNotFoundException("No user to add specified");
1597 User user = dao.getEntityById(User.class, userId);
1598 Group group = dao.getEntityById(Group.class, groupId);
1599 if (!group.getOwner().equals(user))
1600 throw new InsufficientPermissionsException();
1601 User userToAdd = dao.getEntityById(User.class, userToAddId);
1602 if (group.contains(userToAdd))
1603 throw new DuplicateNameException("User already exists in group");
1604 group.getMembers().add(userToAdd);
1610 public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1612 throw new ObjectNotFoundException("No user specified");
1613 User user = dao.getEntityById(User.class, userId);
1614 user.invalidateAuthToken();
1619 public List<FolderDTO> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1621 throw new ObjectNotFoundException("No user specified");
1622 List<Folder> folders = dao.getSharedRootFolders(userId);
1623 List<FolderDTO> result = new ArrayList<FolderDTO>();
1624 for (Folder f : folders) {
1625 FolderDTO dto = f.getDTO();
1626 dto.setSubfolders(getSharedSubfolders(userId, f.getId()));
1633 public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1635 throw new ObjectNotFoundException("No user specified");
1636 if (groupId == null)
1637 throw new ObjectNotFoundException("No group specified");
1638 if (memberId == null)
1639 throw new ObjectNotFoundException("No member specified");
1640 User owner = dao.getEntityById(User.class, userId);
1641 Group group = dao.getEntityById(Group.class, groupId);
1642 User member = dao.getEntityById(User.class, memberId);
1643 if (!group.getOwner().equals(owner))
1644 throw new InsufficientPermissionsException("User is not the owner of the group");
1645 group.removeMemberFromGroup(member);
1651 public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1652 List<User> users = dao.getUsersSharingFoldersForUser(userId);
1653 List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1654 List<UserDTO> res = new ArrayList<UserDTO>();
1655 for (User u : users)
1656 res.add(u.getDTO());
1657 for(User fu : usersFiles)
1658 if(!users.contains(fu))
1659 res.add(fu.getDTO());
1664 public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1666 throw new ObjectNotFoundException("No user specified");
1668 throw new ObjectNotFoundException("No folder specified");
1669 User user = dao.getEntityById(User.class, userId);
1670 FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1671 if(!folder.hasReadPermission(user))
1672 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1673 Set<Permission> perms = folder.getPermissions();
1674 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1675 for (Permission perm : perms)
1676 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1677 result.add(perm.getDTO());
1678 for (Permission perm : perms)
1679 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1681 result.add(perm.getDTO());
1686 * Set the provided permissions as the new permissions of the specified
1687 * file. This method sets the modification date/user attributes to the
1688 * current values as a side effect.
1691 * @param permissions
1692 * @throws ObjectNotFoundException
1693 * @throws InsufficientPermissionsException
1695 private void setFilePermissions(FileHeader file,
1696 Set<PermissionDTO> permissions)
1697 throws ObjectNotFoundException, InsufficientPermissionsException {
1698 if (permissions != null && !permissions.isEmpty()) {
1699 PermissionDTO ownerPerm = null;
1700 for (PermissionDTO dto : permissions)
1701 if (dto.getUser() != null && dto.getUser().getId().equals(file.getOwner().getId())) {
1705 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1706 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1707 // Delete previous entries.
1708 for (Permission perm: file.getPermissions())
1710 file.getPermissions().clear();
1711 for (PermissionDTO dto : permissions) {
1712 // Skip 'empty' permission entries.
1713 if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1714 file.addPermission(getPermission(dto));
1721 public List<FileHeaderDTO> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1723 throw new ObjectNotFoundException("No user specified");
1724 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1725 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1726 for (FileHeader f : files)
1727 result.add(f.getDTO());
1732 public List<FileHeaderDTO> getSharedFiles(Long userId) throws ObjectNotFoundException {
1734 throw new ObjectNotFoundException("No user specified");
1735 List<FileHeader> files = dao.getSharedFiles(userId);
1736 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1737 for (FileHeader f : files)
1738 result.add(f.getDTO());
1743 public List<FolderDTO> getSharedFolders(Long userId) throws ObjectNotFoundException {
1745 throw new ObjectNotFoundException("No user specified");
1746 List<Folder> folders = dao.getSharedFolders(userId);
1747 List<FolderDTO> result = new ArrayList<FolderDTO>();
1748 for (Folder f : folders)
1749 result.add(f.getDTO());
1754 public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1755 if (ownerId == null)
1756 throw new ObjectNotFoundException("No owner specified");
1757 if (callingUserId == null)
1758 throw new ObjectNotFoundException("No calling user specified");
1759 List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1760 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1761 for (FileHeader f : folders)
1762 result.add(f.getDTO());
1767 public List<FolderDTO> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1768 if (ownerId == null)
1769 throw new ObjectNotFoundException("No owner specified");
1770 if (callingUserId == null)
1771 throw new ObjectNotFoundException("No calling user specified");
1772 List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1773 List<FolderDTO> result = new ArrayList<FolderDTO>();
1774 for (Folder f : folders) {
1775 FolderDTO dto = f.getDTO();
1776 dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1784 public List<FolderDTO> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1786 throw new ObjectNotFoundException("No user specified");
1787 if (folderId == null)
1788 throw new ObjectNotFoundException("No folder specified");
1789 User user = dao.getEntityById(User.class, userId);
1790 Folder folder = dao.getEntityById(Folder.class, folderId);
1791 List<FolderDTO> result = new ArrayList<FolderDTO>();
1792 if (folder.isShared(user) || folder.isReadForAll())
1793 for (Folder f : folder.getSubfolders())
1794 if ((f.isShared(user) || f.isReadForAll()) && !f.isDeleted())
1795 result.add(f.getDTO());
1800 public List<FolderDTO> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1802 throw new ObjectNotFoundException("No user specified");
1803 if (callingUserId == null)
1804 throw new ObjectNotFoundException("No user specified");
1805 if (folderId == null)
1806 throw new ObjectNotFoundException("No folder specified");
1807 User user = dao.getEntityById(User.class, callingUserId);
1808 Folder folder = dao.getEntityById(Folder.class, folderId);
1809 List<FolderDTO> result = new ArrayList<FolderDTO>();
1810 if (folder.isSharedForOtherUser(user))
1811 for (Folder f : folder.getSubfolders())
1812 if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1813 FolderDTO dto = f.getDTO();
1814 dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId()));
1822 public List<FileHeader> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1823 long startTime = System.currentTimeMillis();
1825 throw new ObjectNotFoundException("No user specified");
1826 User user = getUser(userId);
1828 throw new ObjectNotFoundException("No query specified");
1829 List<FileHeader> files = search(user.getId(), query);
1831 long stopTime = System.currentTimeMillis();
1832 logger.info("Total time: " + (stopTime - startTime));
1837 * Performs the actuals search on the solr server and returns the results
1841 * @return a List of FileHeader objects
1843 private List<FileHeader> search(Long userId, String query) {
1844 final int maxRows = 100;
1845 List<FileHeader> result = new ArrayList<FileHeader>();
1847 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
1848 List<Group> groups = dao.getGroupsContainingUser(userId);
1849 String constructedQuery = escapeCharacters(normalizeSearchQuery(query)) + " AND (public: true OR ureaders: " + userId;
1850 if (!groups.isEmpty()) {
1851 constructedQuery += " OR (";
1852 for (int i=0; i<groups.size(); i++) {
1853 Group g = groups.get(i);
1854 constructedQuery += "greaders :" + g.getId();
1855 if (i < groups.size() - 1)
1856 constructedQuery += " OR ";
1858 constructedQuery += ")";
1860 constructedQuery += ")";
1861 SolrQuery solrQuery = new SolrQuery(constructedQuery);
1862 solrQuery.setRows(maxRows);
1863 long startTime = System.currentTimeMillis();
1864 QueryResponse response = solr.query(solrQuery);
1865 SolrDocumentList results = response.getResults();
1866 if (results.getNumFound() > maxRows) {
1867 solrQuery.setRows(Integer.valueOf((int) results.getNumFound()));
1868 response = solr.query(solrQuery);
1869 results = response.getResults();
1871 long stopTime = System.currentTimeMillis();
1872 logger.info("Search time:" + (stopTime - startTime));
1873 User user = getUser(userId);
1874 startTime = System.currentTimeMillis();
1875 for (SolrDocument d : results) {
1876 Long id = Long.valueOf((String) d.getFieldValue("id"));
1878 FileHeader f = dao.getEntityById(FileHeader.class, id);
1880 } catch (ObjectNotFoundException e) {
1881 logger.warn("Search result id " + id + " cannot be found", e);
1884 stopTime = System.currentTimeMillis();
1885 logger.info("File loads: " + (stopTime - startTime));
1886 } catch (MalformedURLException e) {
1888 throw new EJBException(e);
1889 } catch (SolrServerException e) {
1891 throw new EJBException(e);
1892 } catch (ObjectNotFoundException e) {
1894 throw new EJBException(e);
1900 public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1901 for(Long l : fileIds){
1902 FileHeader file = dao.getEntityById(FileHeader.class, l);
1903 copyFile(userId, l, destId, file.getName());
1910 public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1911 for(Long l : fileIds){
1912 FileHeader file = dao.getEntityById(FileHeader.class, l);
1913 moveFile(userId, l, destId, file.getName());
1919 public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1921 throw new ObjectNotFoundException("No user specified");
1922 User user = dao.getEntityById(User.class, userId);
1923 Nonce nonce = Nonce.createNonce(user.getId());
1929 public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1931 throw new ObjectNotFoundException("No user specified");
1933 throw new ObjectNotFoundException("No nonce specified");
1934 return dao.getNonce(nonce, userId);
1938 public void removeNonce(Long id) throws ObjectNotFoundException {
1940 throw new ObjectNotFoundException("No nonce specified");
1941 Nonce nonce = dao.getEntityById(Nonce.class, id);
1946 public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1948 throw new ObjectNotFoundException("No user specified");
1949 User user = dao.getEntityById(User.class, userId);
1950 user.setNonce(nonce);
1951 user.setNonceExpiryDate(nonceExpiryDate);
1955 public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1957 throw new ObjectNotFoundException("No user specified");
1958 StatsDTO stats = new StatsDTO();
1959 stats.setFileCount(dao.getFileCount(userId));
1960 Long fileSize = dao.getFileSize(userId);
1961 stats.setFileSize(fileSize);
1962 Long quota = getQuota(userId);
1963 Long quotaLeft = quota - fileSize;
1964 stats.setQuotaLeftSize(quotaLeft);
1969 public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1971 throw new ObjectNotFoundException("No user specified");
1973 throw new ObjectNotFoundException("No file specified");
1974 User user = dao.getEntityById(User.class, userId);
1975 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1976 if(!header.hasReadPermission(user))
1977 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1978 List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
1979 for(int i = header.getBodies().size()-1 ; i>=0; i--)
1980 result.add(header.getBodies().get(i).getDTO());
1985 public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1987 throw new ObjectNotFoundException("No user specified");
1989 throw new ObjectNotFoundException("No file specified");
1990 User user = dao.getEntityById(User.class, userId);
1991 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1992 if(!header.hasWritePermission(user))
1993 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1994 FileBody body = dao.getFileVersion(fileId, version);
1995 final File fileContents = new File(body.getStoredFilePath());
1998 updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
1999 } catch (FileNotFoundException e) {
2000 throw new GSSIOException(e);
2006 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2009 public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2011 throw new ObjectNotFoundException("No user specified");
2013 throw new ObjectNotFoundException("No file specified");
2014 User user = dao.getEntityById(User.class, userId);
2015 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2016 if(!header.hasWritePermission(user))
2017 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2018 Iterator<FileBody> it = header.getBodies().iterator();
2019 while(it.hasNext()){
2020 FileBody body = it.next();
2021 if(!body.equals(header.getCurrentBody())){
2022 deleteActualFile(body.getStoredFilePath());
2027 header.getCurrentBody().setVersion(1);
2029 Folder parent = header.getFolder();
2030 touchParentFolders(parent, user, new Date());
2034 * Gets the quota left for specified user ID.
2036 private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
2037 Long fileSize = dao.getFileSize(userId);
2038 Long quota = getQuota(userId);
2039 return quota - fileSize;
2043 * Gets the quota for specified user ID.
2045 private Long getQuota(Long userId) throws ObjectNotFoundException{
2046 UserClass uc = getUser(userId).getUserClass();
2048 uc = getDefaultUserClass();
2049 return uc.getQuota();
2053 @TransactionAttribute(TransactionAttributeType.NEVER)
2054 public String rebuildSolrIndex() {
2056 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2057 solr.deleteByQuery("*:*");
2059 logger.info("Deleted everything in solr");
2061 List<Long> fileIds = dao.getAllFileIds();
2062 logger.info("Total of " + fileIds.size() + " will be indexed");
2064 for (Long id : fileIds) {
2065 postFileToSolr(solr, id);
2069 logger.info("Sent commit to solr at file " + i);
2074 logger.info("Finished indexing of " + i + " files");
2075 return "Finished indexing of " + i + " files";
2076 } catch (IOException e) {
2077 throw new EJBException(e);
2078 } catch (SolrServerException e) {
2079 throw new EJBException(e);
2084 @TransactionAttribute(TransactionAttributeType.NEVER)
2085 public String refreshSolrIndex() {
2087 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2089 List<Long> fileIds = dao.getAllFileIds();
2090 logger.info("Total of " + fileIds.size() + " will be indexed");
2092 for (Long id : fileIds) {
2093 postFileToSolr(solr, id);
2098 logger.info("Sent commit to solr at file " + i);
2102 logger.info("Finished indexing of " + i + " files");
2103 return "Finished indexing of " + i + " files";
2104 } catch (IOException e) {
2105 throw new EJBException(e);
2106 } catch (SolrServerException e) {
2107 throw new EJBException(e);
2112 public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2113 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2114 InsufficientPermissionsException, QuotaExceededException {
2117 throw new ObjectNotFoundException("No user specified");
2118 if (folderId == null)
2119 throw new ObjectNotFoundException("No folder specified");
2120 String contentType = mimeType;
2121 if (StringUtils.isEmpty(mimeType))
2122 contentType = DEFAULT_MIME_TYPE;
2123 if (StringUtils.isEmpty(name))
2124 throw new ObjectNotFoundException("No file name specified");
2125 if (dao.existsFolderOrFile(folderId, name))
2126 throw new DuplicateNameException("A folder or file with the name '" + name +
2127 "' already exists at this level");
2129 // Do the actual work.
2130 Folder parent = null;
2132 parent = dao.getEntityById(Folder.class, folderId);
2133 } catch (final ObjectNotFoundException onfe) {
2134 // Supply a more accurate problem description.
2135 throw new ObjectNotFoundException("Parent folder not found");
2137 final User owner = dao.getEntityById(User.class, userId);
2138 if (!parent.hasWritePermission(owner))
2139 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2140 final FileHeader file = new FileHeader();
2142 parent.addFile(file);
2143 // set file owner to folder owner
2144 file.setOwner(parent.getOwner());
2145 //set file's readForAll value according to parent folder readForAll value
2146 file.setReadForAll(parent.isReadForAll());
2148 final Date now = new Date();
2149 final AuditInfo auditInfo = new AuditInfo();
2150 auditInfo.setCreatedBy(owner);
2151 auditInfo.setCreationDate(now);
2152 auditInfo.setModifiedBy(owner);
2153 auditInfo.setModificationDate(now);
2154 file.setAuditInfo(auditInfo);
2155 // TODO set the proper versioning flag on creation
2156 file.setVersioned(false);
2158 for (final Permission p : parent.getPermissions()) {
2159 final Permission permission = new Permission();
2160 permission.setGroup(p.getGroup());
2161 permission.setUser(p.getUser());
2162 permission.setRead(p.getRead());
2163 permission.setWrite(p.getWrite());
2164 permission.setModifyACL(p.getModifyACL());
2165 file.addPermission(permission);
2168 // Create the file body.
2170 createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2171 } catch (FileNotFoundException e) {
2172 throw new GSSIOException(e);
2174 touchParentFolders(parent, owner, new Date());
2176 indexFile(file.getId(), false);
2178 return file.getDTO();
2182 public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2184 throw new ObjectNotFoundException("No user specified");
2186 throw new ObjectNotFoundException("No file specified");
2187 String contentType = mimeType;
2189 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2191 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2192 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2193 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2194 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2195 contentType = identifyMimeType(file.getName());
2197 final User owner = dao.getEntityById(User.class, userId);
2198 if (!file.hasWritePermission(owner))
2199 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2200 final Date now = new Date();
2201 final AuditInfo auditInfo = new AuditInfo();
2202 auditInfo.setCreatedBy(owner);
2203 auditInfo.setCreationDate(now);
2204 auditInfo.setModifiedBy(owner);
2205 auditInfo.setModificationDate(now);
2207 createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2208 } catch (FileNotFoundException e) {
2209 throw new GSSIOException(e);
2211 Folder parent = file.getFolder();
2212 touchParentFolders(parent, owner, new Date());
2214 indexFile(fileId, false);
2215 return file.getDTO();
2219 * Helper method for identifying mime type by examining the filename extension
2222 * @return the mime type
2224 private String identifyMimeType(String filename) {
2225 if (filename.indexOf('.') != -1) {
2226 String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2227 if (".doc".equals(extension))
2228 return "application/msword";
2229 else if (".xls".equals(extension))
2230 return "application/vnd.ms-excel";
2231 else if (".ppt".equals(extension))
2232 return "application/vnd.ms-powerpoint";
2233 else if (".pdf".equals(extension))
2234 return "application/pdf";
2235 else if (".gif".equals(extension))
2237 else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2238 return "image/jpeg";
2239 else if (".tiff".equals(extension) || ".tif".equals(extension))
2240 return "image/tiff";
2241 else if (".png".equals(extension))
2243 else if (".bmp".equals(extension))
2246 // when all else fails assign the default mime type
2247 return DEFAULT_MIME_TYPE;
2251 * Helper method to create a new file body and attach it as the current body
2252 * of the provided file header.
2254 * @param name the original file name
2255 * @param mimeType the content type
2256 * @param fileSize the uploaded file size
2257 * @param filePath the uploaded file full path
2258 * @param header the file header that will be associated with the new body
2259 * @param auditInfo the audit info
2260 * @throws FileNotFoundException
2261 * @throws QuotaExceededException
2262 * @throws ObjectNotFoundException if the owner was not found
2264 private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2265 FileHeader header, AuditInfo auditInfo)
2266 throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2268 long currentTotalSize = 0;
2269 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2270 currentTotalSize = header.getTotalSize();
2271 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2272 if(quotaLeft < fileSize-currentTotalSize) {
2273 // quota exceeded -> delete the file
2274 deleteActualFile(filePath);
2275 throw new QuotaExceededException("Not enough free space available");
2278 FileBody body = new FileBody();
2280 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2281 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2282 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2283 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2284 body.setMimeType(identifyMimeType(name));
2286 body.setMimeType(mimeType);
2287 body.setAuditInfo(auditInfo);
2288 body.setFileSize(fileSize);
2289 body.setOriginalFilename(name);
2290 body.setStoredFilePath(filePath);
2291 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2292 if(!header.isVersioned() && header.getCurrentBody() != null){
2293 header.setCurrentBody(null);
2294 if (header.getBodies() != null) {
2295 Iterator<FileBody> it = header.getBodies().iterator();
2296 while(it.hasNext()){
2297 FileBody bo = it.next();
2298 deleteActualFile(bo.getStoredFilePath());
2306 header.addBody(body);
2307 header.setAuditInfo(auditInfo);
2314 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2315 public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2317 throw new ObjectNotFoundException("No user specified");
2318 User owner = dao.getEntityById(User.class, userId);
2320 throw new ObjectNotFoundException("No user specified");
2321 long start = 0, end = 0;
2322 if (logger.isDebugEnabled())
2323 start = System.currentTimeMillis();
2324 File result = new File(generateRepositoryFilePath());
2326 final FileOutputStream output = new FileOutputStream(result);
2327 final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2330 while (-1 != (n = stream.read(buffer)))
2331 output.write(buffer, 0, n);
2334 } catch (IOException e) {
2335 if (!result.delete())
2336 logger.warn("Could not delete " + result.getPath());
2339 if (logger.isDebugEnabled()) {
2340 end = System.currentTimeMillis();
2341 logger.debug("Time to upload: " + (end - start) + " (msec)");
2348 public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2351 throw new ObjectNotFoundException("No user specified");
2352 User user = dao.getEntityById(User.class, userId);
2353 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2355 status = new FileUploadStatus();
2356 status.setOwner(user);
2357 status.setFilename(filename);
2358 status.setBytesUploaded(bytesTransfered);
2359 status.setFileSize(fileSize);
2363 status.setBytesUploaded(bytesTransfered);
2364 status.setFileSize(fileSize);
2371 public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2373 throw new ObjectNotFoundException("No user specified");
2374 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2380 public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2381 return dao.getFileUploadStatus(userId, fileName);
2385 public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2387 throw new ObjectNotFoundException("No user specified");
2388 if (folderId == null)
2389 throw new ObjectNotFoundException("No folder specified");
2390 final User user = dao.getEntityById(User.class, userId);
2391 final Folder folder = dao.getEntityById(Folder.class, folderId);
2392 // Check permissions
2393 if (!folder.hasReadPermission(user))
2394 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2395 List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2396 if (folder.hasReadPermission(user))
2397 for (Folder f : folder.getSubfolders())
2398 if (f.hasReadPermission(user) && !f.isDeleted())
2399 subfolders.add(f.getDTO());
2400 FolderDTO result = folder.getDTO();
2401 result.setSubfolders(subfolders);
2402 return folder.getDTO();
2406 public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2408 throw new ObjectNotFoundException("No user specified");
2409 if (folderId == null)
2410 throw new ObjectNotFoundException("No folder specified");
2411 User user = dao.getEntityById(User.class, callingUserId);
2412 Folder folder = dao.getEntityById(Folder.class, folderId);
2413 // Check permissions
2414 if (!folder.hasReadPermission(user))
2415 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2417 FolderDTO result = folder.getDTO();
2418 result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2423 public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2424 throws ObjectNotFoundException, InsufficientPermissionsException {
2426 throw new ObjectNotFoundException("No user specified");
2428 throw new ObjectNotFoundException("No file specified");
2430 throw new ObjectNotFoundException("No valid version specified");
2431 User user = dao.getEntityById(User.class, userId);
2432 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2433 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2434 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2435 FileBody body = dao.getFileVersion(fileId, version);
2436 return body.getDTO();
2440 public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2442 throw new ObjectNotFoundException("No user specified");
2443 User user = dao.getEntityById(User.class, userId);
2444 user.setAcceptedPolicy(isAccepted);
2449 public void updateAccounting(User user, Date date, long bandwidthDiff) {
2450 dao.updateAccounting(user, date, bandwidthDiff);
2454 public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2456 throw new ObjectNotFoundException("No user specified");
2457 if (folderId == null)
2458 throw new ObjectNotFoundException("No folder specified");
2459 User user = dao.getEntityById(User.class, userId);
2460 Folder folder = dao.getEntityById(Folder.class, folderId);
2461 // Check permissions
2462 if (!folder.hasReadPermission(user))
2468 public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2470 throw new ObjectNotFoundException("No user specified");
2471 User user = dao.getEntityById(User.class, userId);
2472 user.generateWebDAVPassword();
2473 return user.getWebDAVPassword();
2477 public Invitation findInvite(String code) {
2480 return dao.findInvite(code);
2484 public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2485 LDAPConnection lc = new LDAPConnection();
2486 LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2487 attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2488 attributeSet.add(new LDAPAttribute("uid", username));
2489 attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2490 attributeSet.add(new LDAPAttribute("sn", lastname));
2491 attributeSet.add(new LDAPAttribute("givenName", firstname));
2492 attributeSet.add(new LDAPAttribute("mail", email));
2493 attributeSet.add(new LDAPAttribute("userPassword", password));
2494 String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2495 LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2497 lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2498 lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2499 getConfiguration().getString("bindPassword").getBytes("UTF8"));
2501 logger.info("Successfully added LDAP account: " + dn);
2503 } catch(LDAPException e) {
2504 throw new RuntimeException(e);
2505 } catch(UnsupportedEncodingException e) {
2506 throw new RuntimeException(e);
2512 public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2513 User user = findUser(username);
2515 throw new ObjectNotFoundException("The user was not found");
2516 Invitation invite = findInvite(code);
2517 if (invite.getUser() != null)
2518 throw new InvitationUsedException("This code has already been used");
2519 invite.setUser(user);
2520 UserClass couponClass = getCouponUserClass();
2521 user.setUserClass(couponClass);
2526 public UserClass getCouponUserClass() {
2527 return dao.findCouponUserClass();
2531 * Mark the folder as modified from the specified user and change it's modification date.
2533 private void touchFolder(Folder f, User _user, Date now){
2534 final AuditInfo auditInfo = f.getAuditInfo();
2535 auditInfo.setModificationDate(now);
2536 auditInfo.setModifiedBy(_user);
2537 f.setAuditInfo(auditInfo);
2541 * Mark the file as modified from the specified user and change it's modification date.
2543 private void touchFile(FileHeader f, User _user, Date now){
2544 final AuditInfo auditInfo = f.getAuditInfo();
2545 auditInfo.setModificationDate(now);
2546 auditInfo.setModifiedBy(_user);
2547 f.setAuditInfo(auditInfo);
2551 * Set the provided readForAll as the new readforAll value of the specified
2552 * folder and sub-folders.
2557 * @throws ObjectNotFoundException
2560 private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){
2561 if (readForAll != null && user.equals(folder.getOwner())){
2562 folder.setReadForAll(readForAll);
2564 for (FileHeader file : folder.getFiles())
2565 file.setReadForAll(readForAll);
2567 //only update subfolders when readforall is true. otherwise all sub-folders stay untouched
2568 for (Folder sub : folder.getSubfolders())
2569 setFolderReadForAll(user, sub, readForAll);
2576 * Update the userLogin with the values from the supplied object.
2579 public void addUserLogin(UserLogin userLogin) {
2580 dao.update(userLogin);
2585 * Retrieves the current session user login and the user's last login
2588 * @return a list of last two user logins
2589 * @throws ObjectNotFoundException
2592 public List<UserLogin> getLastUserLogins(Long userId) throws ObjectNotFoundException{
2593 List<UserLogin> userLoginResults = new ArrayList<UserLogin>();
2594 userLoginResults = dao.getLoginsForUser(userId);
2595 if(userLoginResults.size() == 0)
2596 throw new ObjectNotFoundException("No userlogin found for the user");
2597 //if the user logins for the first time lastLoginDate = currentLoginDate
2598 if(userLoginResults.size()==1)
2599 userLoginResults.add(userLoginResults.get(0));
2600 return userLoginResults;
2605 public void postFileToSolr(CommonsHttpSolrServer solr, Long id) {
2607 FileHeader file = dao.getFileForIndexing(id);
2608 FileBody body = file.getCurrentBody();
2609 String mime = body.getMimeType();
2610 boolean multipart = true;
2611 if (!mime.equals("application/pdf")
2612 && !mime.equals("text/plain")
2613 && !mime.equals("text/html")
2614 && !mime.endsWith("msword")
2615 && !mime.endsWith("ms-excel")
2616 && !mime.endsWith("powerpoint")
2617 || (body.getFileSize() > getConfiguration().getLong("solrDocumentUploadLimitInKB") * 1024))
2621 sendMetaDataOnly(solr, file);
2623 ContentStreamUpdateRequest solrRequest = new ContentStreamUpdateRequest(getConfiguration().getString("solr.rich.update.path"));
2624 solrRequest.setParam("literal.id", file.getId().toString());
2625 solrRequest.setParam("literal.name", file.getName());
2626 for (FileTag t : file.getFileTags()) {
2627 solrRequest.getParams().add("literal.tag", t.getTag());
2629 for (Permission p : file.getPermissions()) {
2631 if (p.getUser() != null)
2632 solrRequest.setParam("literal.ureaders", p.getUser().getId().toString());
2633 else if (p.getGroup() != null)
2634 solrRequest.setParam("literal.greaders", p.getGroup().getId().toString());
2637 solrRequest.setParam("literal.owner", file.getOwner().getId().toString());
2638 solrRequest.setParam("literal.public", String.valueOf(file.isReadForAll()));
2639 File fsFile = new File(body.getStoredFilePath());
2640 solrRequest.addFile(fsFile);
2642 solr.request(solrRequest);
2644 catch (SolrException e) {
2645 logger.warn("File " + id + " failed with SolrException: " + e.getLocalizedMessage() + ". Retrying without the file");
2646 //Let 's try without the file
2647 sendMetaDataOnly(solr, file);
2649 catch (NullPointerException e) {
2650 logger.warn("File " + id + " failed with NullPointerException: " + e.getLocalizedMessage() + ". Retrying without the file");
2651 //Let 's try without the file
2652 sendMetaDataOnly(solr, file);
2654 catch (SolrServerException e) {
2655 logger.warn("File " + id + " failed with SolrServerException: " + e.getLocalizedMessage() + ". Retrying without the file");
2656 //Let 's try without the file
2657 sendMetaDataOnly(solr, file);
2660 } catch (MalformedURLException e) {
2661 throw new EJBException(e);
2662 } catch (ObjectNotFoundException e) {
2663 logger.error("Indexing of file id " + id + " failed.", e);
2664 } catch (SolrServerException e) {
2665 throw new EJBException(e);
2666 } catch (IOException e) {
2667 throw new EJBException(e);
2671 private void sendMetaDataOnly(CommonsHttpSolrServer solr, FileHeader file) throws SolrServerException, IOException {
2672 SolrInputDocument solrDoc = new SolrInputDocument();
2673 solrDoc.addField("id", file.getId().toString());
2674 solrDoc.addField("name", file.getName());
2675 for (FileTag t : file.getFileTags()) {
2676 solrDoc.addField("tag", t.getTag());
2678 for (Permission p : file.getPermissions()) {
2680 if (p.getUser() != null)
2681 solrDoc.addField("ureaders", p.getUser().getId());
2682 else if (p.getGroup() != null)
2683 solrDoc.addField("greaders", p.getGroup().getId());
2686 solrDoc.addField("owner", file.getOwner().getId());
2687 solrDoc.addField("public", file.isReadForAll());
2691 private String tokenizeFilename(String filename){
2692 StringBuffer result = new StringBuffer();
2693 StringTokenizer tokenizer = new StringTokenizer(filename,"._");
2694 while(tokenizer.hasMoreTokens()){
2695 result.append(tokenizer.nextToken());
2698 result.append(filename);
2699 return result.toString();
2702 private String normalizeSearchQuery(String query) {
2703 if (query.contains("*"))
2704 return query.toLowerCase().replace('ά', 'α').replace('έ', 'ε').replace('ί', 'ι').replace('ή', 'η').replace('ύ', 'υ')
2705 .replace('ό', 'ο').replace('ς', 'σ').replace('ώ', 'ω').replace('ϊ', 'ι').replace('ϋ', 'υ');
2710 private String escapeCharacters(String text) {
2711 return text.replaceAll(":", "\\\\:");