2 * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd.
4 * This file is part of GSS.
6 * GSS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GSS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GSS. If not, see <http://www.gnu.org/licenses/>.
19 package gr.ebs.gss.server.ejb;
21 import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
22 import gr.ebs.gss.client.exceptions.DuplicateNameException;
23 import gr.ebs.gss.client.exceptions.GSSIOException;
24 import gr.ebs.gss.client.exceptions.InsufficientPermissionsException;
25 import gr.ebs.gss.client.exceptions.InvitationUsedException;
26 import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
27 import gr.ebs.gss.client.exceptions.QuotaExceededException;
28 import gr.ebs.gss.server.domain.AuditInfo;
29 import gr.ebs.gss.server.domain.FileBody;
30 import gr.ebs.gss.server.domain.FileHeader;
31 import gr.ebs.gss.server.domain.FileTag;
32 import gr.ebs.gss.server.domain.FileUploadStatus;
33 import gr.ebs.gss.server.domain.Folder;
34 import gr.ebs.gss.server.domain.Group;
35 import gr.ebs.gss.server.domain.Invitation;
36 import gr.ebs.gss.server.domain.Nonce;
37 import gr.ebs.gss.server.domain.Permission;
38 import gr.ebs.gss.server.domain.User;
39 import gr.ebs.gss.server.domain.UserClass;
40 import gr.ebs.gss.server.domain.dto.StatsDTO;
41 import gr.ebs.gss.server.domain.dto.UserDTO;
44 import java.io.FileInputStream;
45 import java.io.FileNotFoundException;
46 import java.io.FileOutputStream;
47 import java.io.IOException;
48 import java.io.InputStream;
49 import java.io.UnsupportedEncodingException;
50 import java.net.MalformedURLException;
51 import java.util.ArrayList;
52 import java.util.Date;
53 import java.util.Iterator;
54 import java.util.LinkedHashSet;
55 import java.util.List;
56 import java.util.Locale;
57 import java.util.Random;
59 import java.util.StringTokenizer;
62 import javax.ejb.EJBException;
63 import javax.ejb.EJBTransactionRolledbackException;
64 import javax.ejb.Stateless;
65 import javax.ejb.TransactionAttribute;
66 import javax.ejb.TransactionAttributeType;
67 import javax.jms.Connection;
68 import javax.jms.ConnectionFactory;
69 import javax.jms.JMSException;
70 import javax.jms.MapMessage;
71 import javax.jms.MessageProducer;
72 import javax.jms.Queue;
73 import javax.jms.QueueConnectionFactory;
74 import javax.jms.Session;
75 import javax.naming.Context;
76 import javax.naming.InitialContext;
77 import javax.naming.NamingException;
78 import javax.persistence.PersistenceException;
80 import org.apache.commons.lang.StringUtils;
81 import org.apache.commons.logging.Log;
82 import org.apache.commons.logging.LogFactory;
83 import org.apache.solr.client.solrj.SolrQuery;
84 import org.apache.solr.client.solrj.SolrServerException;
85 import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
86 import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
87 import org.apache.solr.client.solrj.response.QueryResponse;
88 import org.apache.solr.common.SolrDocument;
89 import org.apache.solr.common.SolrDocumentList;
90 import org.apache.solr.common.SolrException;
91 import org.apache.solr.common.SolrInputDocument;
92 import org.hibernate.exception.ConstraintViolationException;
94 import com.novell.ldap.LDAPAttribute;
95 import com.novell.ldap.LDAPAttributeSet;
96 import com.novell.ldap.LDAPConnection;
97 import com.novell.ldap.LDAPEntry;
98 import com.novell.ldap.LDAPException;
101 * The concrete implementation of the ExternalAPI interface.
106 public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
108 * The default MIME type for files without an explicit one.
110 private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
113 * The size of the buffer that is used to temporarily store chunks of
114 * uploaded files, while storing them to the file repository.
116 private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
121 private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
124 * Injected reference to the GSSDAO data access facade.
131 * A cached random number generator for creating unique filenames.
133 private static Random random = new Random();
136 * Mark the folder and all of its parent folders as modified from the specified user.
138 private void touchParentFolders(Folder folder, User user, Date date) {
141 AuditInfo ai = f.getAuditInfo();
142 ai.setModifiedBy(user);
143 ai.setModificationDate(date);
150 public Folder getRootFolder(Long userId) throws ObjectNotFoundException {
152 throw new ObjectNotFoundException("No user specified");
153 Folder folder = dao.getRootFolder(userId);
158 public Folder getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
160 throw new ObjectNotFoundException("No user specified");
161 if (folderId == null)
162 throw new ObjectNotFoundException("No folder specified");
163 final User user = dao.getEntityById(User.class, userId);
164 final Folder folder = dao.getEntityById(Folder.class, folderId);
166 if (!folder.hasReadPermission(user))
167 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
172 public User getUser(Long userId) throws ObjectNotFoundException {
174 throw new ObjectNotFoundException("No user specified");
175 return dao.getEntityById(User.class, userId);
179 public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
180 return getUser(userId).getDTO();
184 public Group getGroup(final Long groupId) throws ObjectNotFoundException {
186 throw new ObjectNotFoundException("No group specified");
187 final Group group = dao.getEntityById(Group.class, groupId);
192 public Group getGroup(Long userId, String name) throws ObjectNotFoundException {
194 throw new ObjectNotFoundException("No user specified");
196 throw new ObjectNotFoundException("No group specified");
197 User user = dao.getEntityById(User.class, userId);
198 List<Group> groups = user.getGroupsSpecified();
199 for (Group group: groups)
200 if (group.getName().equals(name))
202 throw new ObjectNotFoundException("Group " + name + " not found");
206 public List<Group> getGroups(final Long userId) throws ObjectNotFoundException {
208 throw new ObjectNotFoundException("No user specified");
209 final List<Group> groups = dao.getGroups(userId);
214 public List<FileHeader> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
215 throws ObjectNotFoundException, InsufficientPermissionsException {
218 throw new ObjectNotFoundException("No user specified");
219 if (folderId == null)
220 throw new ObjectNotFoundException("No folder specified");
221 User user = dao.getEntityById(User.class, userId);
222 Folder folder = dao.getEntityById(Folder.class, folderId);
223 if (!folder.hasReadPermission(user))
224 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
225 List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
230 public List<User> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
233 throw new ObjectNotFoundException("No user specified");
235 throw new ObjectNotFoundException("No group specified");
237 // Do the actual work.
238 final List<User> users = dao.getUsers(groupId);
243 public Folder createFolder(Long userId, Long parentId, String name)
244 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
247 throw new ObjectNotFoundException("No user specified");
248 if (StringUtils.isEmpty(name))
249 throw new ObjectNotFoundException("New folder name is empty");
250 if (parentId == null)
251 throw new ObjectNotFoundException("No parent specified");
252 if (dao.existsFolderOrFile(parentId, name))
253 throw new DuplicateNameException("A folder or file with the name '" +
254 name + "' already exists at this level");
256 User creator = dao.getEntityById(User.class, userId);
258 Folder parent = null;
260 parent = dao.getEntityById(Folder.class, parentId);
261 } catch (ObjectNotFoundException onfe) {
262 // Supply a more accurate problem description.
263 throw new ObjectNotFoundException("Parent folder not found");
265 if (!parent.hasWritePermission(creator))
266 throw new InsufficientPermissionsException("You don't have the permissions" +
267 " to write to this folder");
269 // Do the actual work.
270 return createFolder(name, parent, creator);
274 * Create a new folder with the provided name, parent and owner.
279 * @return the new folder
281 private Folder createFolder(String name, Folder parent, User creator) {
282 Folder folder = new Folder();
283 folder.setName(name);
284 if (parent != null) {
285 parent.addSubfolder(folder);
286 folder.setOwner(parent.getOwner());
288 folder.setOwner(creator);
290 Date now = new Date();
291 AuditInfo auditInfo = new AuditInfo();
292 auditInfo.setCreatedBy(creator);
293 auditInfo.setCreationDate(now);
294 auditInfo.setModifiedBy(creator);
295 auditInfo.setModificationDate(now);
296 folder.setAuditInfo(auditInfo);
297 touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
300 for (Permission p : parent.getPermissions()) {
301 Permission permission = new Permission();
302 permission.setGroup(p.getGroup());
303 permission.setUser(p.getUser());
304 permission.setRead(p.getRead());
305 permission.setWrite(p.getWrite());
306 permission.setModifyACL(p.getModifyACL());
307 folder.addPermission(permission);
310 Permission permission = new Permission();
311 permission.setUser(creator);
312 permission.setRead(true);
313 permission.setWrite(true);
314 permission.setModifyACL(true);
315 folder.addPermission(permission);
319 folder.setReadForAll(parent.isReadForAll());
326 public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
329 throw new ObjectNotFoundException("No user specified");
330 if (folderId == null)
331 throw new ObjectNotFoundException("No folder specified");
333 // Do the actual work.
334 final Folder folder = dao.getEntityById(Folder.class, folderId);
335 final Folder parent = folder.getParent();
337 throw new ObjectNotFoundException("Deleting the root folder is not allowed");
338 final User user = dao.getEntityById(User.class, userId);
339 if (!folder.hasDeletePermission(user)) {
340 logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
341 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
343 removeSubfolderFiles(folder);
344 parent.removeSubfolder(folder);
346 touchParentFolders(parent, user, new Date());
350 * Traverses the folder and deletes all actual files (file system)
351 * regardless of permissions
355 private void removeSubfolderFiles(Folder folder) {
356 //remove files for all subfolders
357 for (Folder subfolder:folder.getSubfolders())
358 removeSubfolderFiles(subfolder);
359 //remove this folder's file bodies (actual files)
360 for (FileHeader file:folder.getFiles()) {
361 for (FileBody body:file.getBodies())
362 deleteActualFile(body.getStoredFilePath());
363 indexFile(file.getId(), true);
368 @SuppressWarnings("unchecked")
369 public List<Folder> getSubfolders(Long userId, Long folderId)
370 throws ObjectNotFoundException, InsufficientPermissionsException {
372 throw new ObjectNotFoundException("No user specified");
373 if (folderId == null)
374 throw new ObjectNotFoundException("No folder specified");
375 User user = dao.getEntityById(User.class, userId);
376 Folder folder = dao.getEntityById(Folder.class, folderId);
377 if (!folder.hasReadPermission(user))
378 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
379 List<Folder> result = new ArrayList<Folder>();
380 if (folder.hasReadPermission(user))
381 for (Folder f : folder.getSubfolders())
382 if (f.hasReadPermission(user) && !f.isDeleted())
388 public Folder updateFolder(Long userId, Long folderId, String folderName,
390 Set<Permission> permissions)
391 throws InsufficientPermissionsException, ObjectNotFoundException,
392 DuplicateNameException {
396 throw new ObjectNotFoundException("No user specified");
397 if (folderId == null)
398 throw new ObjectNotFoundException("No folder specified");
400 Folder folder = dao.getEntityById(Folder.class, folderId);
401 User user = dao.getEntityById(User.class, userId);
402 if (folderName != null && !folder.hasWritePermission(user))
403 throw new InsufficientPermissionsException("You don't have the necessary permissions");
404 if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
405 throw new InsufficientPermissionsException("You don't have the necessary permissions");
406 // Check permissions for making file public.
407 if (readForAll != null && !user.equals(folder.getOwner()))
408 throw new InsufficientPermissionsException("Only the owner can make a folder public or not public");
410 Folder parent = folder.getParent();
411 if (folderName != null) {
413 if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
414 throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
416 // Do the actual modification.
417 folder.setName(folderName);
419 if (permissions != null)
420 setFolderPermissions(user, folder, permissions);
421 if (readForAll != null)
422 setFolderReadForAll(user, folder, readForAll);
423 folder.getAuditInfo().setModificationDate(new Date());
424 folder.getAuditInfo().setModifiedBy(user);
426 touchParentFolders(folder, user, new Date());
431 public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
434 throw new ObjectNotFoundException("No user specified");
435 if (StringUtils.isEmpty(name))
436 throw new ObjectNotFoundException("New group name is empty");
437 if (name.indexOf('/')>=0)
438 throw new IllegalArgumentException("Character '/' is not allowed in group name");
439 if (dao.existsGroup(userId, name))
440 throw new DuplicateNameException("A group with the name '" + name + "' already exists");
442 // TODO: Check permissions
444 final User owner = dao.getEntityById(User.class, userId);
446 // Do the actual work.
447 owner.createGroup(name);
451 public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
454 throw new ObjectNotFoundException("No user specified");
456 throw new ObjectNotFoundException("No group specified");
458 // Do the actual work.
459 final User owner = dao.getEntityById(User.class, userId);
460 final Group group = dao.getEntityById(Group.class, groupId);
461 final Date now = new Date();
462 // Only delete the group if actually owned by the user.
463 if (group.getOwner().equals(owner)) {
464 List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
465 for (Folder f : folders){
466 f.getPermissions().removeAll(group.getPermissions());
467 touchFolder(f, owner, now);
468 for(FileHeader file : f.getFiles()){
469 file.getPermissions().removeAll(group.getPermissions());
470 touchFile(file, owner, now);
473 List<FileHeader> files = dao.getFilesPermittedForGroup(userId, groupId);
474 for(FileHeader h : files){
475 h.getPermissions().removeAll(group.getPermissions());
476 touchFile(h, owner, now);
478 owner.removeSpecifiedGroup(group);
481 else throw new InsufficientPermissionsException("You are not the owner of this group");
485 public FileHeader createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
486 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
487 InsufficientPermissionsException, QuotaExceededException {
490 file = uploadFile(stream, userId);
491 } catch ( IOException ioe) {
492 // Supply a more accurate problem description.
493 throw new GSSIOException("Problem creating file",ioe);
495 return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
499 * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
502 public void indexFile(Long fileId, boolean delete) {
503 Connection qConn = null;
504 Session session = null;
505 MessageProducer sender = null;
507 Context jndiCtx = new InitialContext();
508 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
509 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
510 qConn = factory.createConnection();
511 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
512 sender = session.createProducer(queue);
514 MapMessage map = session.createMapMessage();
515 map.setObject("id", fileId);
516 map.setBoolean("delete", delete);
519 catch (NamingException e) {
520 logger.error("Index was not updated: ", e);
522 catch (JMSException e) {
523 logger.error("Index was not updated: ", e);
534 catch (JMSException e) {
543 * A helper method that generates a unique file path for a stored file. The
544 * files are stored using random hash names that are distributed evenly in
545 * a 2-level tree of subdirectories named after the first two hex characters
546 * in the name. For example, file ab1234cd5769f will be stored in the path
547 * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
548 * if they don't already exist.
550 * @return a unique new file path
552 private String generateRepositoryFilePath() {
553 String filename = Long.toHexString(random.nextLong());
554 String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
555 File root = new File(fileRepositoryPath);
558 File firstFolder = new File(root + File.separator + filename.substring(0, 1));
559 if (!firstFolder.exists())
561 File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
562 if (!secondFolder.exists())
563 secondFolder.mkdir();
564 return secondFolder + File.separator + filename;
568 public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
571 throw new ObjectNotFoundException("No user specified");
573 throw new ObjectNotFoundException("No file specified");
575 // Do the actual work.
576 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
577 final Folder parent = file.getFolder();
579 throw new ObjectNotFoundException("The specified file has no parent folder");
580 final User user = dao.getEntityById(User.class, userId);
581 if (!file.hasDeletePermission(user))
582 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
583 for (final FileBody body : file.getBodies())
584 deleteActualFile(body.getStoredFilePath());
586 touchParentFolders(parent, user, new Date());
587 indexFile(fileId, true);
591 public void deleteActualFile(String path) {
594 File file = new File(path);
596 logger.error("Could not delete file " + path);
600 public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
602 throw new ObjectNotFoundException("No user specified");
603 if (fileHeaderId == null)
604 throw new ObjectNotFoundException("No file specified");
605 if (StringUtils.isEmpty(tag))
606 throw new ObjectNotFoundException("Tag is empty");
608 final User user = dao.getEntityById(User.class, userId);
609 final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
610 final Folder parent = fh.getFolder();
612 throw new ObjectNotFoundException("The specified file has no parent folder");
613 user.addTag(fh, tag);
614 touchParentFolders(parent, user, new Date());
618 public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
619 return dao.getUserTags(userId);
623 public void updateFile(Long userId, Long fileId, String name,
624 String tagSet, Date modificationDate, Boolean versioned,
625 Boolean readForAll, Set<Permission> permissions)
626 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
628 throw new ObjectNotFoundException("No user specified");
630 throw new ObjectNotFoundException("No file specified");
631 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
632 final Folder parent = file.getFolder();
634 throw new ObjectNotFoundException("The specified file has no parent folder");
636 User user = dao.getEntityById(User.class, userId);
637 // Check permissions for modifying the file metadata.
638 if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
639 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
640 // Check permissions for making file public.
641 if (readForAll != null && !user.equals(file.getOwner()))
642 throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
643 // Check permissions for modifying the ACL.
644 if(permissions != null && !permissions.isEmpty() && !file.hasModifyACLPermission(user))
645 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update the permissions on file " + file.getName() + "(" + file.getId() + ")");
648 // Do plain check for file already exists.
649 // Extreme concurrency case should be caught by constraint violation later.
650 if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
654 if (modificationDate != null)
655 file.getAuditInfo().setModificationDate(modificationDate);
657 file.getAuditInfo().setModificationDate(new Date());
658 file.getAuditInfo().setModifiedBy(user);
660 List<FileTag> tags = file.getFileTags();
661 if (tagSet != null) {
662 Iterator<FileTag> i = tags.iterator();
663 while (i.hasNext()) {
664 FileTag tag = i.next();
671 StringTokenizer st = new StringTokenizer(tagSet, ",");
672 while (st.hasMoreTokens())
673 new FileTag(user, file, st.nextToken().trim());
675 if (versioned != null && !file.isVersioned() == versioned) {
676 if (file.isVersioned())
677 removeOldVersions(userId, fileId);
678 file.setVersioned(versioned);
680 if (readForAll != null && user.equals(file.getOwner()))
681 file.setReadForAll(readForAll);
682 if (permissions != null && !permissions.isEmpty())
683 setFilePermissions(file, permissions);
686 * Force constraint violation to manifest itself here.
687 * This should cover extreme concurrency cases that the simple check
688 * above hasn't caught.
693 catch (EJBTransactionRolledbackException e) {
694 Throwable cause = e.getCause();
695 if (cause instanceof PersistenceException && cause.getCause() instanceof ConstraintViolationException)
696 throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
700 touchParentFolders(parent, user, new Date());
702 // Re-index the file if it was modified.
703 if (name != null || tagSet != null)
704 indexFile(fileId, false);
708 public InputStream getFileContents(Long userId, Long fileId)
709 throws ObjectNotFoundException, InsufficientPermissionsException {
711 throw new ObjectNotFoundException("No user specified");
713 throw new ObjectNotFoundException("No file specified");
715 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
716 User user = dao.getEntityById(User.class, userId);
717 if (!header.hasReadPermission(user)) {
718 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
719 throw new InsufficientPermissionsException("You don't have the necessary permissions");
722 File f = new File(header.getCurrentBody().getStoredFilePath());
724 return new FileInputStream(f);
725 } catch (FileNotFoundException e) {
726 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
727 throw new ObjectNotFoundException("The file contents could not be located");
732 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
735 public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
737 throw new ObjectNotFoundException("No user specified");
739 throw new ObjectNotFoundException("No file specified");
741 throw new ObjectNotFoundException("No file specified");
743 final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
744 final FileBody body = dao.getEntityById(FileBody.class, bodyId);
745 final User user = dao.getEntityById(User.class, userId);
746 if (!header.hasReadPermission(user)) {
747 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
748 throw new InsufficientPermissionsException("You don't have the necessary permissions");
751 File f = new File(body.getStoredFilePath());
753 return new FileInputStream(f);
754 } catch (FileNotFoundException e) {
755 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
756 throw new ObjectNotFoundException("The file contents could not be located");
761 public FileHeader getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
763 throw new ObjectNotFoundException("No user specified");
765 throw new ObjectNotFoundException("No file specified");
766 final User user = dao.getEntityById(User.class, userId);
767 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
768 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
769 throw new InsufficientPermissionsException("You don't have the necessary permissions");
774 public FileBody getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
776 throw new ObjectNotFoundException("No user specified");
778 throw new ObjectNotFoundException("No file specified");
779 User user = dao.getEntityById(User.class, userId);
780 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
781 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
782 throw new InsufficientPermissionsException("You don't have the necessary permissions");
783 FileBody body = dao.getEntityById(FileBody.class, bodyId);
788 public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
789 throws ObjectNotFoundException {
791 throw new ObjectNotFoundException("No user specified");
792 if (StringUtils.isEmpty(path))
793 throw new ObjectNotFoundException("No path specified");
795 User owner = dao.getEntityById(User.class, ownerId);
796 List<String> pathElements = new ArrayList<String>();
797 StringTokenizer st = new StringTokenizer(path, "/");
798 while (st.hasMoreTokens())
799 pathElements.add(st.nextToken());
800 if (pathElements.size() < 1)
801 return getRootFolder(owner.getId());
802 // Store the last element, since it requires special handling.
803 String lastElement = pathElements.remove(pathElements.size() - 1);
804 Folder cursor = getRootFolder(owner.getId());
805 // Traverse and verify the specified folder path.
806 for (String pathElement : pathElements) {
807 cursor = getFolder(cursor.getId(), pathElement);
808 if (cursor.isDeleted())
809 throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
812 // Use the lastElement to retrieve the actual resource.
813 Object resource = null;
815 FileHeader file = getFile(cursor.getId(), lastElement);
816 if (ignoreDeleted && file.isDeleted())
817 throw new ObjectNotFoundException("Resource not found");
819 } catch (ObjectNotFoundException e) {
820 // Perhaps the requested resource is not a file, so
821 // check for folders as well.
822 Folder folder = getFolder(cursor.getId(), lastElement);
823 if (ignoreDeleted && folder.isDeleted())
824 throw new ObjectNotFoundException("Resource not found");
832 * Retrieve a file for the specified user that has the specified name and
833 * its parent folder has id equal to folderId.
835 * @param folderId the ID of the parent folder
836 * @param name the name of the requested file
837 * @return the file found
838 * @throws ObjectNotFoundException if the specified folder or file was not
839 * found, with the exception message mentioning the precise
842 private FileHeader getFile(Long folderId, String name) throws ObjectNotFoundException {
843 if (folderId == null)
844 throw new ObjectNotFoundException("No parent folder specified");
845 if (StringUtils.isEmpty(name))
846 throw new ObjectNotFoundException("No file specified");
848 FileHeader file = dao.getFile(folderId, name);
853 * Retrieve a folder for the specified user that has the specified name and
854 * its parent folder has id equal to parentId.
856 * @param parentId the ID of the parent folder
857 * @param name the name of the requested folder
858 * @return the folder found
859 * @throws ObjectNotFoundException if the specified folder or parent was not
860 * found, with the exception message mentioning the precise
863 private Folder getFolder(Long parentId, String name) throws ObjectNotFoundException {
864 if (parentId == null)
865 throw new ObjectNotFoundException("No parent folder specified");
866 if (StringUtils.isEmpty(name))
867 throw new ObjectNotFoundException("No folder specified");
869 Folder folder = dao.getFolder(parentId, name);
873 private FileHeader updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
876 file = uploadFile(resourceInputStream, userId);
877 } catch ( IOException ioe) {
878 // Supply a more accurate problem description.
879 throw new GSSIOException("Problem creating file",ioe);
881 return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
885 public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
887 throw new ObjectNotFoundException("No user specified");
889 throw new ObjectNotFoundException("No file specified");
890 if (StringUtils.isEmpty(dest))
891 throw new ObjectNotFoundException("No destination specified");
893 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
894 if (!(destination instanceof Folder))
895 throw new ObjectNotFoundException("Destination parent folder not found");
896 Folder parent = (Folder) destination;
897 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
901 public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
903 throw new ObjectNotFoundException("No user specified");
905 throw new ObjectNotFoundException("No owner specified");
907 throw new ObjectNotFoundException("No file specified");
908 if (StringUtils.isEmpty(dest))
909 throw new ObjectNotFoundException("No destination specified");
911 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
912 if (!(destination instanceof Folder))
913 throw new ObjectNotFoundException("Destination parent folder not found");
914 Folder parent = (Folder) destination;
915 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
919 public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
921 throw new ObjectNotFoundException("No user specified");
923 throw new ObjectNotFoundException("No file specified");
925 throw new ObjectNotFoundException("No destination specified");
926 if (StringUtils.isEmpty(destName))
927 throw new ObjectNotFoundException("No destination file name specified");
929 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
930 Folder destination = dao.getEntityById(Folder.class, destId);
931 User user = dao.getEntityById(User.class, userId);
932 if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
933 throw new InsufficientPermissionsException("You don't have the necessary permissions");
934 boolean versioned = file.isVersioned();
935 int versionsNumber = file.getBodies().size();
936 FileBody oldestBody = file.getBodies().get(0);
937 assert oldestBody != null;
938 File contents = new File(oldestBody.getStoredFilePath());
940 createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
941 FileHeader copiedFile = dao.getFile(destination.getId(), destName);
942 copiedFile.setVersioned(versioned);
944 if (versionsNumber > 1)
945 for (int i = 1; i < versionsNumber; i++) {
946 FileBody body = file.getBodies().get(i);
948 contents = new File(body.getStoredFilePath());
949 updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
951 List<FileTag> tags = file.getFileTags();
952 for (FileTag tag : tags)
953 createTag(userId, copiedFile.getId(), tag.getTag());
955 } catch (FileNotFoundException e) {
956 throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
962 public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
964 throw new ObjectNotFoundException("No user specified");
965 if (folderId == null)
966 throw new ObjectNotFoundException("No folder specified");
967 if (StringUtils.isEmpty(dest))
968 throw new ObjectNotFoundException("No destination specified");
970 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
971 if (!(destination instanceof Folder))
972 throw new ObjectNotFoundException("Destination folder not found");
973 Folder parent = (Folder) destination;
974 copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
978 public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
980 throw new ObjectNotFoundException("No user specified");
981 if (folderId == null)
982 throw new ObjectNotFoundException("No folder specified");
984 throw new ObjectNotFoundException("No destination specified");
985 if (StringUtils.isEmpty(destName))
986 throw new ObjectNotFoundException("No destination folder name specified");
987 Folder folder = dao.getEntityById(Folder.class, folderId);
988 Folder destination = dao.getEntityById(Folder.class, destId);
989 User user = dao.getEntityById(User.class, userId);
990 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
991 throw new InsufficientPermissionsException("You don't have the necessary permissions");
992 createFolder(user.getId(), destination.getId(), destName);
996 public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
998 throw new ObjectNotFoundException("No user specified");
1000 throw new ObjectNotFoundException("No owner specified");
1001 if (folderId == null)
1002 throw new ObjectNotFoundException("No folder specified");
1003 if (StringUtils.isEmpty(dest))
1004 throw new ObjectNotFoundException("No destination specified");
1006 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1007 if (!(destination instanceof Folder))
1008 throw new ObjectNotFoundException("Destination folder not found");
1009 Folder parent = (Folder) destination;
1010 copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1014 public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1016 throw new ObjectNotFoundException("No user specified");
1017 if (folderId == null)
1018 throw new ObjectNotFoundException("No folder specified");
1020 throw new ObjectNotFoundException("No destination specified");
1021 if (StringUtils.isEmpty(destName))
1022 throw new ObjectNotFoundException("No destination folder name specified");
1024 Folder folder = dao.getEntityById(Folder.class, folderId);
1025 Folder destination = dao.getEntityById(Folder.class, destId);
1026 final User user = dao.getEntityById(User.class, userId);
1027 // XXX: quick fix need to copy only visible items to user (Source
1029 if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1031 if(folder.isDeleted())//do not copy trashed folder and contents
1033 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1034 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1035 createFolder(user.getId(), destination.getId(), destName);
1036 Folder createdFolder = dao.getFolder(destination.getId(), destName);
1037 List<FileHeader> files = folder.getFiles();
1039 for (FileHeader file : files)
1040 if(!file.isDeleted())
1041 copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1042 List<Folder> subFolders = folder.getSubfolders();
1043 if (subFolders != null)
1044 for (Folder sub : subFolders)
1045 if(!sub.getId().equals(createdFolder.getId()))
1046 copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1051 * For a provided path, remove the last element and return the rest, that is
1052 * the path of the parent folder.
1054 * @param path the specified path
1055 * @return the path of the parent folder
1056 * @throws ObjectNotFoundException if the provided string contains no path
1059 private String getParentPath(String path) throws ObjectNotFoundException {
1060 int lastDelimiter = path.lastIndexOf('/');
1061 if (lastDelimiter == 0)
1063 if (lastDelimiter == -1)
1065 throw new ObjectNotFoundException("There is no parent in the path: " + path);
1066 else if (lastDelimiter < path.length() - 1)
1067 // Return the part before the delimiter.
1068 return path.substring(0, lastDelimiter);
1070 // Remove the trailing delimiter and then recurse.
1071 String strippedTrail = path.substring(0, lastDelimiter);
1072 return getParentPath(strippedTrail);
1077 * Get the last element in a path that denotes the file or folder name.
1079 * @param path the provided path
1080 * @return the last element in the path
1082 private String getLastElement(String path) {
1083 int lastDelimiter = path.lastIndexOf('/');
1084 if (lastDelimiter == -1)
1087 else if (lastDelimiter < path.length() - 1)
1088 // Return the part after the delimiter.
1089 return path.substring(lastDelimiter + 1);
1091 // Remove the trailing delimiter and then recurse.
1092 String strippedTrail = path.substring(0, lastDelimiter);
1093 return getLastElement(strippedTrail);
1098 public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1100 throw new ObjectNotFoundException("No user specified");
1102 throw new ObjectNotFoundException("No file specified");
1104 // Do the actual work.
1105 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1106 Folder parent = file.getFolder();
1108 throw new ObjectNotFoundException("The specified file has no parent folder");
1109 User user = dao.getEntityById(User.class, userId);
1110 if (!file.hasDeletePermission(user))
1111 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1113 file.setDeleted(true);
1115 touchParentFolders(parent, user, new Date());
1119 public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1121 throw new ObjectNotFoundException("No user specified");
1122 if (ownerId == null)
1123 throw new ObjectNotFoundException("No owner specified");
1125 throw new ObjectNotFoundException("No file specified");
1126 if (StringUtils.isEmpty(dest))
1127 throw new ObjectNotFoundException("No destination specified");
1129 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1130 if (!(destination instanceof Folder))
1131 throw new ObjectNotFoundException("Destination parent folder not found");
1132 Folder parent = (Folder) destination;
1133 moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1137 public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1139 throw new ObjectNotFoundException("No user specified");
1141 throw new ObjectNotFoundException("No file specified");
1143 throw new ObjectNotFoundException("No destination specified");
1144 if (StringUtils.isEmpty(destName))
1145 throw new ObjectNotFoundException("No destination file name specified");
1147 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1148 Folder source = file.getFolder();
1149 Folder destination = dao.getEntityById(Folder.class, destId);
1151 User owner = dao.getEntityById(User.class, userId);
1152 if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1153 throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1155 // if the destination folder belongs to another user:
1156 if (!file.getOwner().equals(destination.getOwner())) {
1157 // (a) check if the destination quota allows the move
1158 if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1159 throw new QuotaExceededException("Not enough free space available");
1160 User newOwner = destination.getOwner();
1161 // (b) if quota OK, change the owner of the file
1162 file.setOwner(newOwner);
1163 // if the file has no permission for the new owner, add it
1164 Permission ownerPermission = null;
1165 for (final Permission p : file.getPermissions())
1166 if (p.getUser() != null)
1167 if (p.getUser().equals(newOwner)) {
1168 ownerPermission = p;
1171 if (ownerPermission == null) {
1172 ownerPermission = new Permission();
1173 ownerPermission.setUser(newOwner);
1174 file.addPermission(ownerPermission);
1176 ownerPermission.setRead(true);
1177 ownerPermission.setWrite(true);
1178 ownerPermission.setModifyACL(true);
1180 // move the file to the destination folder
1181 file.setFolder(destination);
1182 touchParentFolders(source, owner, new Date());
1183 touchParentFolders(destination, owner, new Date());
1187 public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1189 throw new ObjectNotFoundException("No user specified");
1190 if (ownerId == null)
1191 throw new ObjectNotFoundException("No owner specified");
1192 if (folderId == null)
1193 throw new ObjectNotFoundException("No folder specified");
1194 if (StringUtils.isEmpty(dest))
1195 throw new ObjectNotFoundException("No destination specified");
1197 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1198 if (!(destination instanceof Folder))
1199 throw new ObjectNotFoundException("Destination parent folder not found");
1200 Folder parent = (Folder) destination;
1201 moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1205 public void moveFolder(Long userId, Long folderId, Long destId, String destName)
1206 throws ObjectNotFoundException, InsufficientPermissionsException,
1207 QuotaExceededException {
1208 Folder source = dao.getEntityById(Folder.class, folderId);
1209 Folder destination = dao.getEntityById(Folder.class, destId);
1210 User user = dao.getEntityById(User.class, userId);
1211 User sourceOwner = source.getOwner();
1212 User destinationOwner = destination.getOwner();
1213 // Do not move trashed folders and contents.
1214 if (source.isDeleted())
1216 // Check permissions.
1217 if (!destination.hasWritePermission(user)
1218 || !source.hasReadPermission(user)
1219 || !source.hasWritePermission(user))
1220 throw new InsufficientPermissionsException("You don't have the " +
1221 "necessary permissions");
1222 // Use the same timestamp for all subsequent modifications to make
1223 // changes appear simultaneous.
1224 Date now = new Date();
1225 // If source and destination are not in the same user's namespace,
1226 // change owners and check quota.
1227 if (!sourceOwner.equals(destinationOwner)) {
1228 changeOwner(source, destinationOwner, user, now);
1229 if (getQuotaLeft(destinationOwner.getId()) < 0)
1230 throw new QuotaExceededException("Not enough free space " +
1231 "available in destination folder");
1233 // Perform the move.
1234 Folder oldParent = source.getParent();
1235 oldParent.removeSubfolder(source);
1236 destination.addSubfolder(source);
1237 // Mark the former parent and destination trees upwards as modified.
1238 touchParentFolders(oldParent, user, now);
1239 touchParentFolders(source, user, now);
1243 * Recursively change the owner of the specified folder and all of its
1244 * contents to the specified owner. Also mark them all as modified with the
1245 * specified modifier and modificationDate.
1247 private void changeOwner(Folder folder, User owner, User modifier, Date modificationDate) {
1248 for (FileHeader file: folder.getFiles()) {
1249 file.setOwner(owner);
1250 file.getAuditInfo().setModificationDate(modificationDate);
1251 file.getAuditInfo().setModifiedBy(modifier);
1253 for (Folder sub: folder.getSubfolders())
1254 changeOwner(sub, owner, modifier, modificationDate);
1255 folder.setOwner(owner);
1256 folder.getAuditInfo().setModificationDate(modificationDate);
1257 folder.getAuditInfo().setModifiedBy(modifier);
1261 public List<FileHeader> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1264 throw new ObjectNotFoundException("No user specified");
1266 // Do the actual work.
1267 final List<FileHeader> files = dao.getDeletedFiles(userId);
1272 public void removeFileFromTrash(Long userId, Long fileId)
1273 throws ObjectNotFoundException, InsufficientPermissionsException {
1275 throw new ObjectNotFoundException("No user specified");
1277 throw new ObjectNotFoundException("No file specified");
1279 // Do the actual work.
1280 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1281 Folder parent = file.getFolder();
1283 throw new ObjectNotFoundException("The specified file has no parent folder");
1284 User user = dao.getEntityById(User.class, userId);
1285 if (!file.hasDeletePermission(user))
1286 throw new InsufficientPermissionsException("User " + user.getUsername() +
1287 " cannot restore file " + file.getName());
1289 file.setDeleted(false);
1291 touchParentFolders(parent, user, new Date());
1295 public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1297 throw new ObjectNotFoundException("No user specified");
1298 if (folderId == null)
1299 throw new ObjectNotFoundException("No folder specified");
1300 Folder folder = dao.getEntityById(Folder.class, folderId);
1301 User user = dao.getEntityById(User.class, userId);
1302 if (!folder.hasDeletePermission(user))
1303 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1304 folder.setDeleted(true);
1306 touchParentFolders(folder, user, new Date());
1307 for (FileHeader file : folder.getFiles())
1308 moveFileToTrash(userId, file.getId());
1309 for (Folder subFolder : folder.getSubfolders())
1310 moveFolderToTrash(userId, subFolder.getId());
1315 public void removeFolderFromTrash(Long userId, Long folderId)
1316 throws ObjectNotFoundException, InsufficientPermissionsException {
1318 throw new ObjectNotFoundException("No user specified");
1319 if (folderId == null)
1320 throw new ObjectNotFoundException("No folder specified");
1321 Folder folder = dao.getEntityById(Folder.class, folderId);
1322 User user = dao.getEntityById(User.class, userId);
1323 if (!folder.hasDeletePermission(user))
1324 throw new InsufficientPermissionsException("User " + user.getUsername() +
1325 " cannot restore folder " + folder.getName());
1326 folder.setDeleted(false);
1327 for (FileHeader file : folder.getFiles())
1328 removeFileFromTrash(userId, file.getId());
1329 for (Folder subFolder : folder.getSubfolders())
1330 removeFolderFromTrash(userId, subFolder.getId());
1332 touchParentFolders(folder, user, new Date());
1336 public List<Folder> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1337 List<Folder> folders = dao.getDeletedRootFolders(userId);
1342 public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1343 List<Folder> deletedRootFolders = getDeletedRootFolders(userId);
1344 for (Folder folder : deletedRootFolders)
1345 deleteFolder(userId, folder.getId());
1346 List<FileHeader> deletedFiles = getDeletedFiles(userId);
1347 for (FileHeader file : deletedFiles)
1348 deleteFile(userId, file.getId());
1352 public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1353 List<Folder> deletedRootFolders = getDeletedRootFolders(userId);
1354 for (Folder folder : deletedRootFolders)
1355 removeFolderFromTrash(userId, folder.getId());
1356 List<FileHeader> deletedFiles = getDeletedFiles(userId);
1357 for (FileHeader file : deletedFiles)
1358 removeFileFromTrash(userId, file.getId());
1362 public User createUser(String username, String name, String mail,
1363 String idp, String idpid) throws ObjectNotFoundException {
1364 if (username == null)
1365 throw new ObjectNotFoundException("No username specified");
1367 throw new ObjectNotFoundException("No name specified");
1369 User user = new User();
1370 user.setUsername(username);
1372 user.setEmail(mail);
1373 user.setIdentityProvider(idp);
1374 user.setIdentityProviderId(idpid);
1375 Date now = new Date();
1376 AuditInfo auditInfo = new AuditInfo();
1377 auditInfo.setCreationDate(now);
1378 auditInfo.setModificationDate(now);
1379 user.setAuditInfo(auditInfo);
1380 user.setActive(true);
1381 user.generateAuthToken();
1382 user.generateWebDAVPassword();
1383 user.setUserClass(getDefaultUserClass());
1385 // Make sure we get an ID in the user object.
1387 // Create the root folder for the user.
1388 createFolder(user.getName(), null, user);
1393 * Get the default user class, which is the one with the lowest quota.
1395 private UserClass getDefaultUserClass() {
1396 return getUserClasses().get(0);
1400 public List<UserClass> getUserClasses() {
1401 List<UserClass> classes = dao.getUserClasses();
1402 // Create a default user class for first-time use. Afterwards, the
1403 // admin should modify or add to the userclass table.
1404 if (classes.size() == 0) {
1405 UserClass defaultClass = new UserClass();
1406 defaultClass.setName("default");
1407 Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L));
1408 defaultClass.setQuota(defaultQuota);
1409 dao.create(defaultClass);
1410 classes.add(defaultClass);
1416 public User findUserByEmail(String email) {
1417 return dao.findUserByEmail(email);
1421 public void updateUser(User user) {
1426 public User findUser(String username) {
1427 if (username == null)
1429 return dao.findUser(username);
1433 public User updateUserToken(Long userId) throws ObjectNotFoundException {
1435 throw new ObjectNotFoundException("No user specified");
1436 User user = dao.getEntityById(User.class, userId);
1437 user.generateAuthToken();
1442 public Set<Permission> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1444 throw new ObjectNotFoundException("No user specified");
1445 if (folderId == null)
1446 throw new ObjectNotFoundException("No folder specified");
1447 User user = dao.getEntityById(User.class, userId);
1448 Folder folder = dao.getEntityById(Folder.class, folderId);
1449 if(!folder.hasReadPermission(user))
1450 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1451 Set<Permission> perms = folder.getPermissions();
1452 Set<Permission> result = new LinkedHashSet<Permission>();
1453 for (Permission perm : perms)
1454 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1456 for (Permission perm : perms)
1457 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1465 * Set the provided permissions as the new permissions of the specified
1470 * @param permissions
1471 * @throws ObjectNotFoundException
1472 * @throws InsufficientPermissionsException
1474 private void setFolderPermissions(User user, Folder folder, Set<Permission> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1475 if (permissions != null && !permissions.isEmpty()) {
1476 User owner = folder.getOwner();
1477 Permission ownerPerm = null;
1478 for (Permission perm : permissions)
1479 if (perm.getUser() != null && perm.getUser().getId().equals(owner.getId())) {
1483 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1484 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1485 // Delete previous entries
1486 for (Permission perm: folder.getPermissions())
1488 folder.getPermissions().clear();
1489 for (Permission p : permissions) {
1490 // Skip 'empty' permission entries.
1491 if (!p.getRead() && !p.getWrite() && !p.getModifyACL()) continue;
1492 folder.addPermission(getPermission(p));
1495 for (FileHeader file : folder.getFiles()) {
1496 setFilePermissions(file, permissions);
1497 Date now = new Date();
1498 file.getAuditInfo().setModificationDate(now);
1499 file.getAuditInfo().setModifiedBy(user);
1501 for (Folder sub : folder.getSubfolders())
1502 setFolderPermissions(user, sub, permissions);
1506 private Permission getPermission(Permission perm) throws ObjectNotFoundException {
1507 Permission res = new Permission();
1508 if (perm.getGroup() != null)
1509 res.setGroup(dao.getEntityById(Group.class, perm.getGroup().getId()));
1510 else if (perm.getUser() != null)
1511 if (perm.getUser().getId() == null)
1512 res.setUser(dao.getUser(perm.getUser().getUsername()));
1514 res.setUser(dao.getEntityById(User.class, perm.getUser().getId()));
1515 res.setRead(perm.hasRead());
1516 res.setWrite(perm.hasWrite());
1517 res.setModifyACL(perm.hasModifyACL());
1522 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1525 public List<User> getUsersByUserNameLike(String username) {
1526 List<User> users = dao.getUsersByUserNameLike(username);
1532 public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1534 throw new ObjectNotFoundException("No user specified");
1535 if (groupId == null)
1536 throw new ObjectNotFoundException("No group specified");
1537 if (userToAddId == null)
1538 throw new ObjectNotFoundException("No user to add specified");
1539 User user = dao.getEntityById(User.class, userId);
1540 Group group = dao.getEntityById(Group.class, groupId);
1541 if (!group.getOwner().equals(user))
1542 throw new InsufficientPermissionsException();
1543 User userToAdd = dao.getEntityById(User.class, userToAddId);
1544 if (group.contains(userToAdd))
1545 throw new DuplicateNameException("User already exists in group");
1546 group.getMembers().add(userToAdd);
1552 public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1554 throw new ObjectNotFoundException("No user specified");
1555 User user = dao.getEntityById(User.class, userId);
1556 user.invalidateAuthToken();
1561 public List<Folder> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1563 throw new ObjectNotFoundException("No user specified");
1564 List<Folder> folders = dao.getSharedRootFolders(userId);
1565 List<Folder> result = new ArrayList<Folder>();
1566 for (Folder f : folders) {
1568 lf.setSubfolders(getSharedSubfolders(userId, f.getId()));
1575 public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1577 throw new ObjectNotFoundException("No user specified");
1578 if (groupId == null)
1579 throw new ObjectNotFoundException("No group specified");
1580 if (memberId == null)
1581 throw new ObjectNotFoundException("No member specified");
1582 User owner = dao.getEntityById(User.class, userId);
1583 Group group = dao.getEntityById(Group.class, groupId);
1584 User member = dao.getEntityById(User.class, memberId);
1585 if (!group.getOwner().equals(owner))
1586 throw new InsufficientPermissionsException("User is not the owner of the group");
1587 group.removeMemberFromGroup(member);
1593 public List<User> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1594 List<User> users = dao.getUsersSharingFoldersForUser(userId);
1595 List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1596 List<User> result = new ArrayList<User>();
1597 for (User u : users)
1599 for(User fu : usersFiles)
1600 if(!users.contains(fu))
1606 public Set<Permission> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1608 throw new ObjectNotFoundException("No user specified");
1610 throw new ObjectNotFoundException("No folder specified");
1611 User user = dao.getEntityById(User.class, userId);
1612 FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1613 if(!folder.hasReadPermission(user))
1614 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1615 Set<Permission> perms = folder.getPermissions();
1616 Set<Permission> result = new LinkedHashSet<Permission>();
1617 for (Permission perm : perms)
1618 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1620 for (Permission perm : perms)
1621 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1628 * Set the provided permissions as the new permissions of the specified
1629 * file. This method sets the modification date/user attributes to the
1630 * current values as a side effect.
1633 * @param permissions
1634 * @throws ObjectNotFoundException
1635 * @throws InsufficientPermissionsException
1637 private void setFilePermissions(FileHeader file,
1638 Set<Permission> permissions)
1639 throws ObjectNotFoundException, InsufficientPermissionsException {
1640 if (permissions != null && !permissions.isEmpty()) {
1641 Permission ownerPerm = null;
1642 for (Permission perm : permissions)
1643 if (perm.getUser() != null && perm.getUser().getId().equals(file.getOwner().getId())) {
1647 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1648 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1649 // Delete previous entries.
1650 for (Permission perm: file.getPermissions())
1652 file.getPermissions().clear();
1653 for (Permission perm : permissions) {
1654 // Skip 'empty' permission entries.
1655 if (!perm.getRead() && !perm.getWrite() && !perm.getModifyACL()) continue;
1656 file.addPermission(getPermission(perm));
1663 public List<FileHeader> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1665 throw new ObjectNotFoundException("No user specified");
1666 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1671 public List<FileHeader> getSharedFiles(Long userId) throws ObjectNotFoundException {
1673 throw new ObjectNotFoundException("No user specified");
1674 List<FileHeader> files = dao.getSharedFiles(userId);
1679 public List<Folder> getSharedFolders(Long userId) throws ObjectNotFoundException {
1681 throw new ObjectNotFoundException("No user specified");
1682 List<Folder> folders = dao.getSharedFolders(userId);
1687 public List<FileHeader> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1688 if (ownerId == null)
1689 throw new ObjectNotFoundException("No owner specified");
1690 if (callingUserId == null)
1691 throw new ObjectNotFoundException("No calling user specified");
1692 List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1697 public List<Folder> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1698 if (ownerId == null)
1699 throw new ObjectNotFoundException("No owner specified");
1700 if (callingUserId == null)
1701 throw new ObjectNotFoundException("No calling user specified");
1702 List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1703 List<Folder> result = new ArrayList<Folder>();
1704 for (Folder f : folders) {
1706 lf.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1714 public List<Folder> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1716 throw new ObjectNotFoundException("No user specified");
1717 if (folderId == null)
1718 throw new ObjectNotFoundException("No folder specified");
1719 User user = dao.getEntityById(User.class, userId);
1720 Folder folder = dao.getEntityById(Folder.class, folderId);
1721 List<Folder> result = new ArrayList<Folder>();
1722 if (folder.isShared(user) || folder.isReadForAll())
1723 for (Folder f : folder.getSubfolders())
1724 if ((f.isShared(user) || f.isReadForAll()) && !f.isDeleted())
1730 public List<Folder> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1732 throw new ObjectNotFoundException("No user specified");
1733 if (callingUserId == null)
1734 throw new ObjectNotFoundException("No user specified");
1735 if (folderId == null)
1736 throw new ObjectNotFoundException("No folder specified");
1737 User user = dao.getEntityById(User.class, callingUserId);
1738 Folder folder = dao.getEntityById(Folder.class, folderId);
1739 List<Folder> result = new ArrayList<Folder>();
1740 if (folder.isSharedForOtherUser(user))
1741 for (Folder f : folder.getSubfolders())
1742 if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1744 lf.setSubfolders(getSharedSubfolders(userId, callingUserId, lf.getId()));
1752 public List<FileHeader> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1753 long startTime = System.currentTimeMillis();
1755 throw new ObjectNotFoundException("No user specified");
1756 User user = getUser(userId);
1758 throw new ObjectNotFoundException("No query specified");
1759 List<FileHeader> files = search(user.getId(), query);
1761 long stopTime = System.currentTimeMillis();
1762 logger.info("Total time: " + (stopTime - startTime));
1767 * Performs the actuals search on the solr server and returns the results
1771 * @return a List of FileHeader objects
1773 private List<FileHeader> search(Long userId, String query) {
1774 final int maxRows = 100;
1775 List<FileHeader> result = new ArrayList<FileHeader>();
1777 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
1778 SolrQuery solrQuery = new SolrQuery(escapeCharacters(normalizeSearchQuery(query)));
1779 solrQuery.setRows(maxRows);
1780 long startTime = System.currentTimeMillis();
1781 QueryResponse response = solr.query(solrQuery);
1782 SolrDocumentList results = response.getResults();
1783 if (results.getNumFound() > maxRows) {
1784 solrQuery.setRows(Integer.valueOf((int) results.getNumFound()));
1785 response = solr.query(solrQuery);
1786 results = response.getResults();
1788 long stopTime = System.currentTimeMillis();
1789 logger.info("Search time:" + (stopTime - startTime));
1790 User user = getUser(userId);
1791 startTime = System.currentTimeMillis();
1792 for (SolrDocument d : results) {
1793 Long id = Long.valueOf((String) d.getFieldValue("id"));
1795 FileHeader f = dao.getEntityById(FileHeader.class, id);
1796 if (f.hasReadPermission(user))
1798 } catch (ObjectNotFoundException e) {
1799 logger.warn("Search result id " + id + " cannot be found", e);
1802 stopTime = System.currentTimeMillis();
1803 logger.info("Permission checks: " + (stopTime - startTime));
1804 } catch (MalformedURLException e) {
1806 throw new EJBException(e);
1807 } catch (SolrServerException e) {
1809 throw new EJBException(e);
1810 } catch (ObjectNotFoundException e) {
1812 throw new EJBException(e);
1818 public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1819 for(Long l : fileIds){
1820 FileHeader file = dao.getEntityById(FileHeader.class, l);
1821 copyFile(userId, l, destId, file.getName());
1828 public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1829 for(Long l : fileIds){
1830 FileHeader file = dao.getEntityById(FileHeader.class, l);
1831 moveFile(userId, l, destId, file.getName());
1837 public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1839 throw new ObjectNotFoundException("No user specified");
1840 final User user = dao.getEntityById(User.class, userId);
1841 List<String> filesToRemove = new ArrayList<String>();
1842 //first delete database objects
1843 for(Long fileId : fileIds){
1845 throw new ObjectNotFoundException("No file specified");
1846 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1847 final Folder parent = file.getFolder();
1849 throw new ObjectNotFoundException("The specified file has no parent folder");
1850 if (!file.hasDeletePermission(user))
1851 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1853 parent.removeFile(file);
1854 for (final FileBody body : file.getBodies())
1855 filesToRemove.add(body.getStoredFilePath());
1857 touchParentFolders(parent, user, new Date());
1859 //then remove physical files if everything is ok
1860 for(String physicalFileName : filesToRemove)
1861 deleteActualFile(physicalFileName);
1862 //then unindex deleted files
1863 for(Long fileId : fileIds)
1864 indexFile(fileId, true);
1869 public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1870 for(Long l : fileIds)
1871 moveFileToTrash(userId, l);
1876 public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1877 for(Long l : fileIds)
1878 removeFileFromTrash(userId, l);
1883 public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1885 throw new ObjectNotFoundException("No user specified");
1886 User user = dao.getEntityById(User.class, userId);
1887 Nonce nonce = Nonce.createNonce(user.getId());
1893 public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1895 throw new ObjectNotFoundException("No user specified");
1897 throw new ObjectNotFoundException("No nonce specified");
1898 return dao.getNonce(nonce, userId);
1902 public void removeNonce(Long id) throws ObjectNotFoundException {
1904 throw new ObjectNotFoundException("No nonce specified");
1905 Nonce nonce = dao.getEntityById(Nonce.class, id);
1910 public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1912 throw new ObjectNotFoundException("No user specified");
1913 User user = dao.getEntityById(User.class, userId);
1914 user.setNonce(nonce);
1915 user.setNonceExpiryDate(nonceExpiryDate);
1919 public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1921 throw new ObjectNotFoundException("No user specified");
1922 StatsDTO stats = new StatsDTO();
1923 stats.setFileCount(dao.getFileCount(userId));
1924 Long fileSize = dao.getFileSize(userId);
1925 stats.setFileSize(fileSize);
1926 Long quota = getQuota(userId);
1927 Long quotaLeft = quota - fileSize;
1928 stats.setQuotaLeftSize(quotaLeft);
1933 public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
1935 throw new ObjectNotFoundException("No user specified");
1937 throw new ObjectNotFoundException("No file specified");
1939 throw new ObjectNotFoundException("No body specified");
1940 User user = dao.getEntityById(User.class, userId);
1941 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1942 if(!header.hasWritePermission(user))
1943 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1944 FileBody body = dao.getEntityById(FileBody.class, bodyId);
1945 if(body.equals(header.getCurrentBody())){
1947 if(header.getBodies().size() == 1)
1948 throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
1949 for(FileBody b : header.getBodies())
1950 if(b.getVersion() == body.getVersion()-1)
1951 header.setCurrentBody(b);
1953 deleteActualFile(body.getStoredFilePath());
1954 header.getBodies().remove(body);
1956 Folder parent = header.getFolder();
1957 touchParentFolders(parent, user, new Date());
1962 public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1964 throw new ObjectNotFoundException("No user specified");
1966 throw new ObjectNotFoundException("No file specified");
1967 User user = dao.getEntityById(User.class, userId);
1968 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1969 if(!header.hasWritePermission(user))
1970 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1971 FileBody body = dao.getFileVersion(fileId, version);
1972 final File fileContents = new File(body.getStoredFilePath());
1975 updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
1976 } catch (FileNotFoundException e) {
1977 throw new GSSIOException(e);
1983 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
1986 public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1988 throw new ObjectNotFoundException("No user specified");
1990 throw new ObjectNotFoundException("No file specified");
1991 User user = dao.getEntityById(User.class, userId);
1992 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1993 if(!header.hasWritePermission(user))
1994 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1995 Iterator<FileBody> it = header.getBodies().iterator();
1996 while(it.hasNext()){
1997 FileBody body = it.next();
1998 if(!body.equals(header.getCurrentBody())){
1999 deleteActualFile(body.getStoredFilePath());
2004 header.getCurrentBody().setVersion(1);
2006 Folder parent = header.getFolder();
2007 touchParentFolders(parent, user, new Date());
2011 * Gets the quota left for specified user ID.
2013 private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
2014 Long fileSize = dao.getFileSize(userId);
2015 Long quota = getQuota(userId);
2016 return quota - fileSize;
2020 * Gets the quota for specified user ID.
2022 private Long getQuota(Long userId) throws ObjectNotFoundException{
2023 UserClass uc = getUser(userId).getUserClass();
2025 uc = getDefaultUserClass();
2026 return uc.getQuota();
2030 @TransactionAttribute(TransactionAttributeType.NEVER)
2031 public String rebuildSolrIndex() {
2033 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2034 solr.deleteByQuery("*:*");
2036 logger.info("Deleted everything in solr");
2038 List<Long> fileIds = dao.getAllFileIds();
2039 logger.info("Total of " + fileIds.size() + " will be indexed");
2041 for (Long id : fileIds) {
2042 postFileToSolr(solr, id);
2046 logger.info("Sent commit to solr at file " + i);
2051 logger.info("Finished indexing of " + i + " files");
2052 return "Finished indexing of " + i + " files";
2053 } catch (IOException e) {
2054 throw new EJBException(e);
2055 } catch (SolrServerException e) {
2056 throw new EJBException(e);
2061 @TransactionAttribute(TransactionAttributeType.NEVER)
2062 public String refreshSolrIndex() {
2064 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2066 List<Long> fileIds = dao.getAllFileIds();
2067 logger.info("Total of " + fileIds.size() + " will be indexed");
2069 for (Long id : fileIds) {
2070 postFileToSolr(solr, id);
2075 logger.debug("Sent commit to solr at file " + i);
2079 logger.info("Finished indexing of " + i + " files");
2080 return "Finished indexing of " + i + " files";
2081 } catch (IOException e) {
2082 throw new EJBException(e);
2083 } catch (SolrServerException e) {
2084 throw new EJBException(e);
2089 public FileHeader createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2090 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2091 InsufficientPermissionsException, QuotaExceededException {
2094 throw new ObjectNotFoundException("No user specified");
2095 if (folderId == null)
2096 throw new ObjectNotFoundException("No folder specified");
2097 String contentType = mimeType;
2098 if (StringUtils.isEmpty(mimeType))
2099 contentType = DEFAULT_MIME_TYPE;
2100 if (StringUtils.isEmpty(name))
2101 throw new ObjectNotFoundException("No file name specified");
2102 if (dao.existsFolderOrFile(folderId, name))
2103 throw new DuplicateNameException("A folder or file with the name '" + name +
2104 "' already exists at this level");
2106 // Do the actual work.
2107 Folder parent = null;
2109 parent = dao.getEntityById(Folder.class, folderId);
2110 } catch (final ObjectNotFoundException onfe) {
2111 // Supply a more accurate problem description.
2112 throw new ObjectNotFoundException("Parent folder not found");
2114 final User owner = dao.getEntityById(User.class, userId);
2115 if (!parent.hasWritePermission(owner))
2116 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2117 final FileHeader file = new FileHeader();
2119 parent.addFile(file);
2120 // set file owner to folder owner
2121 file.setOwner(parent.getOwner());
2122 //set file's readForAll value according to parent folder readForAll value
2123 file.setReadForAll(parent.isReadForAll());
2125 final Date now = new Date();
2126 final AuditInfo auditInfo = new AuditInfo();
2127 auditInfo.setCreatedBy(owner);
2128 auditInfo.setCreationDate(now);
2129 auditInfo.setModifiedBy(owner);
2130 auditInfo.setModificationDate(now);
2131 file.setAuditInfo(auditInfo);
2132 // TODO set the proper versioning flag on creation
2133 file.setVersioned(false);
2135 for (final Permission p : parent.getPermissions()) {
2136 final Permission permission = new Permission();
2137 permission.setGroup(p.getGroup());
2138 permission.setUser(p.getUser());
2139 permission.setRead(p.getRead());
2140 permission.setWrite(p.getWrite());
2141 permission.setModifyACL(p.getModifyACL());
2142 file.addPermission(permission);
2145 // Create the file body.
2147 createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2148 } catch (FileNotFoundException e) {
2149 throw new GSSIOException(e);
2151 touchParentFolders(parent, owner, new Date());
2153 indexFile(file.getId(), false);
2159 public FileHeader updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2161 throw new ObjectNotFoundException("No user specified");
2163 throw new ObjectNotFoundException("No file specified");
2164 String contentType = mimeType;
2166 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2168 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2169 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2170 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2171 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2172 contentType = identifyMimeType(file.getName());
2174 final User owner = dao.getEntityById(User.class, userId);
2175 if (!file.hasWritePermission(owner))
2176 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2177 final Date now = new Date();
2178 final AuditInfo auditInfo = new AuditInfo();
2179 auditInfo.setCreatedBy(owner);
2180 auditInfo.setCreationDate(now);
2181 auditInfo.setModifiedBy(owner);
2182 auditInfo.setModificationDate(now);
2184 createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2185 } catch (FileNotFoundException e) {
2186 throw new GSSIOException(e);
2188 Folder parent = file.getFolder();
2189 touchParentFolders(parent, owner, new Date());
2191 indexFile(fileId, false);
2196 * Helper method for identifying mime type by examining the filename extension
2199 * @return the mime type
2201 private String identifyMimeType(String filename) {
2202 if (filename.indexOf('.') != -1) {
2203 String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2204 if (".doc".equals(extension))
2205 return "application/msword";
2206 else if (".xls".equals(extension))
2207 return "application/vnd.ms-excel";
2208 else if (".ppt".equals(extension))
2209 return "application/vnd.ms-powerpoint";
2210 else if (".pdf".equals(extension))
2211 return "application/pdf";
2212 else if (".gif".equals(extension))
2214 else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2215 return "image/jpeg";
2216 else if (".tiff".equals(extension) || ".tif".equals(extension))
2217 return "image/tiff";
2218 else if (".png".equals(extension))
2220 else if (".bmp".equals(extension))
2223 // when all else fails assign the default mime type
2224 return DEFAULT_MIME_TYPE;
2228 * Helper method to create a new file body and attach it as the current body
2229 * of the provided file header.
2231 * @param name the original file name
2232 * @param mimeType the content type
2233 * @param fileSize the uploaded file size
2234 * @param filePath the uploaded file full path
2235 * @param header the file header that will be associated with the new body
2236 * @param auditInfo the audit info
2237 * @throws FileNotFoundException
2238 * @throws QuotaExceededException
2239 * @throws ObjectNotFoundException if the owner was not found
2241 private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2242 FileHeader header, AuditInfo auditInfo)
2243 throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2245 long currentTotalSize = 0;
2246 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2247 currentTotalSize = header.getTotalSize();
2248 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2249 if(quotaLeft < fileSize-currentTotalSize) {
2250 // quota exceeded -> delete the file
2251 deleteActualFile(filePath);
2252 throw new QuotaExceededException("Not enough free space available");
2255 FileBody body = new FileBody();
2257 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2258 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2259 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2260 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2261 body.setMimeType(identifyMimeType(name));
2263 body.setMimeType(mimeType);
2264 body.setAuditInfo(auditInfo);
2265 body.setFileSize(fileSize);
2266 body.setOriginalFilename(name);
2267 body.setStoredFilePath(filePath);
2268 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2269 if(!header.isVersioned() && header.getCurrentBody() != null){
2270 header.setCurrentBody(null);
2271 if (header.getBodies() != null) {
2272 Iterator<FileBody> it = header.getBodies().iterator();
2273 while(it.hasNext()){
2274 FileBody bo = it.next();
2275 deleteActualFile(bo.getStoredFilePath());
2283 header.addBody(body);
2284 header.setAuditInfo(auditInfo);
2291 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2292 public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2294 throw new ObjectNotFoundException("No user specified");
2295 User owner = dao.getEntityById(User.class, userId);
2297 throw new ObjectNotFoundException("No user specified");
2298 long start = 0, end = 0;
2299 if (logger.isDebugEnabled())
2300 start = System.currentTimeMillis();
2301 File result = new File(generateRepositoryFilePath());
2303 final FileOutputStream output = new FileOutputStream(result);
2304 final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2307 while (-1 != (n = stream.read(buffer)))
2308 output.write(buffer, 0, n);
2311 } catch (IOException e) {
2312 if (!result.delete())
2313 logger.warn("Could not delete " + result.getPath());
2316 if (logger.isDebugEnabled()) {
2317 end = System.currentTimeMillis();
2318 logger.debug("Time to upload: " + (end - start) + " (msec)");
2325 public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2328 throw new ObjectNotFoundException("No user specified");
2329 User user = dao.getEntityById(User.class, userId);
2330 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2332 status = new FileUploadStatus();
2333 status.setOwner(user);
2334 status.setFilename(filename);
2335 status.setBytesUploaded(bytesTransfered);
2336 status.setFileSize(fileSize);
2340 status.setBytesUploaded(bytesTransfered);
2341 status.setFileSize(fileSize);
2348 public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2350 throw new ObjectNotFoundException("No user specified");
2351 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2357 public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2358 return dao.getFileUploadStatus(userId, fileName);
2362 public FileBody getFileVersion(Long userId, Long fileId, int version)
2363 throws ObjectNotFoundException, InsufficientPermissionsException {
2365 throw new ObjectNotFoundException("No user specified");
2367 throw new ObjectNotFoundException("No file specified");
2369 throw new ObjectNotFoundException("No valid version specified");
2370 User user = dao.getEntityById(User.class, userId);
2371 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2372 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2373 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2374 FileBody body = dao.getFileVersion(fileId, version);
2379 public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2381 throw new ObjectNotFoundException("No user specified");
2382 User user = dao.getEntityById(User.class, userId);
2383 user.setAcceptedPolicy(isAccepted);
2388 public void updateAccounting(User user, Date date, long bandwidthDiff) {
2389 dao.updateAccounting(user, date, bandwidthDiff);
2393 public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2395 throw new ObjectNotFoundException("No user specified");
2396 if (folderId == null)
2397 throw new ObjectNotFoundException("No folder specified");
2398 User user = dao.getEntityById(User.class, userId);
2399 Folder folder = dao.getEntityById(Folder.class, folderId);
2400 // Check permissions
2401 if (!folder.hasReadPermission(user))
2407 public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2409 throw new ObjectNotFoundException("No user specified");
2410 User user = dao.getEntityById(User.class, userId);
2411 user.generateWebDAVPassword();
2412 return user.getWebDAVPassword();
2416 public Invitation findInvite(String code) {
2419 return dao.findInvite(code);
2423 public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2424 LDAPConnection lc = new LDAPConnection();
2425 LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2426 attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2427 attributeSet.add(new LDAPAttribute("uid", username));
2428 attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2429 attributeSet.add(new LDAPAttribute("sn", lastname));
2430 attributeSet.add(new LDAPAttribute("givenName", firstname));
2431 attributeSet.add(new LDAPAttribute("mail", email));
2432 attributeSet.add(new LDAPAttribute("userPassword", password));
2433 String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2434 LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2436 lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2437 lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2438 getConfiguration().getString("bindPassword").getBytes("UTF8"));
2440 logger.info("Successfully added LDAP account: " + dn);
2442 } catch(LDAPException e) {
2443 throw new RuntimeException(e);
2444 } catch(UnsupportedEncodingException e) {
2445 throw new RuntimeException(e);
2451 public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2452 User user = findUser(username);
2454 throw new ObjectNotFoundException("The user was not found");
2455 Invitation invite = findInvite(code);
2456 if (invite.getUser() != null)
2457 throw new InvitationUsedException("This code has already been used");
2458 invite.setUser(user);
2459 UserClass couponClass = getCouponUserClass();
2460 user.setUserClass(couponClass);
2465 public UserClass getCouponUserClass() {
2466 return dao.findCouponUserClass();
2470 * Mark the folder as modified from the specified user and change it's modification date.
2472 private void touchFolder(Folder f, User _user, Date now){
2473 final AuditInfo auditInfo = f.getAuditInfo();
2474 auditInfo.setModificationDate(now);
2475 auditInfo.setModifiedBy(_user);
2476 f.setAuditInfo(auditInfo);
2480 * Mark the file as modified from the specified user and change it's modification date.
2482 private void touchFile(FileHeader f, User _user, Date now){
2483 final AuditInfo auditInfo = f.getAuditInfo();
2484 auditInfo.setModificationDate(now);
2485 auditInfo.setModifiedBy(_user);
2486 f.setAuditInfo(auditInfo);
2490 * Set the provided readForAll as the new readforAll value of the specified
2491 * folder and sub-folders.
2496 * @throws ObjectNotFoundException
2499 private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){
2500 if (readForAll != null && user.equals(folder.getOwner())){
2501 folder.setReadForAll(readForAll);
2503 for (FileHeader file : folder.getFiles())
2504 file.setReadForAll(readForAll);
2506 //only update subfolders when readforall is true. otherwise all sub-folders stay untouched
2507 for (Folder sub : folder.getSubfolders())
2508 setFolderReadForAll(user, sub, readForAll);
2515 public void postFileToSolr(CommonsHttpSolrServer solr, Long id) {
2517 FileHeader file = dao.getFileForIndexing(id);
2518 FileBody body = file.getCurrentBody();
2519 String mime = body.getMimeType();
2520 boolean multipart = true;
2521 if (!mime.equals("application/pdf")
2522 && !mime.equals("text/plain")
2523 && !mime.equals("text/html")
2524 && !mime.endsWith("msword")
2525 && !mime.endsWith("ms-excel")
2526 && !mime.endsWith("powerpoint")
2527 || (body.getFileSize() > getConfiguration().getLong("solrDocumentUploadLimitInKB") * 1024))
2531 sendMetaDataOnly(solr, file);
2533 ContentStreamUpdateRequest solrRequest = new ContentStreamUpdateRequest(getConfiguration().getString("solr.rich.update.path"));
2534 solrRequest.setParam("literal.id", file.getId().toString());
2535 solrRequest.setParam("literal.name", file.getName());
2536 for (FileTag t : file.getFileTags()) {
2537 solrRequest.getParams().add("literal.tag", t.getTag());
2539 File fsFile = new File(body.getStoredFilePath());
2540 solrRequest.addFile(fsFile);
2541 // solrRequest.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
2543 solr.request(solrRequest);
2545 catch (SolrException e) {
2546 logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2547 //Let 's try without the file
2548 sendMetaDataOnly(solr, file);
2550 catch (NullPointerException e) {
2551 logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2552 //Let 's try without the file
2553 sendMetaDataOnly(solr, file);
2555 catch (SolrServerException e) {
2556 logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2557 //Let 's try without the file
2558 sendMetaDataOnly(solr, file);
2561 } catch (MalformedURLException e) {
2562 throw new EJBException(e);
2563 } catch (ObjectNotFoundException e) {
2564 logger.error("Indexing of file id " + id + " failed.", e);
2565 } catch (SolrServerException e) {
2566 throw new EJBException(e);
2567 } catch (IOException e) {
2568 throw new EJBException(e);
2572 private void sendMetaDataOnly(CommonsHttpSolrServer solr, FileHeader file) throws SolrServerException, IOException {
2573 SolrInputDocument solrDoc = new SolrInputDocument();
2574 solrDoc.addField("id", file.getId().toString());
2575 solrDoc.addField("name", file.getName());
2576 for (FileTag t : file.getFileTags()) {
2577 solrDoc.addField("tag", t.getTag());
2582 private String tokenizeFilename(String filename){
2583 StringBuffer result = new StringBuffer();
2584 StringTokenizer tokenizer = new StringTokenizer(filename,"._");
2585 while(tokenizer.hasMoreTokens()){
2586 result.append(tokenizer.nextToken());
2589 result.append(filename);
2590 return result.toString();
2593 private String normalizeSearchQuery(String query) {
2594 if (query.contains("*"))
2595 return query.toLowerCase().replace('ά', 'α').replace('έ', 'ε').replace('ί', 'ι').replace('ή', 'η').replace('ύ', 'υ')
2596 .replace('ό', 'ο').replace('ς', 'σ').replace('ώ', 'ω').replace('ϊ', 'ι').replace('ϋ', 'υ');
2601 private String escapeCharacters(String text) {
2602 return text.replaceAll(":", "\\\\:");
2605 /*** NEW METHODS IN ORDER TO AVOID LAZY loading exception in json render
2608 public Folder expandFolder(Folder folder) throws ObjectNotFoundException{
2609 Folder result = dao.getEntityById(Folder.class, folder.getId());
2610 result.getSubfolders().size();
2611 result.getFiles().size();
2612 result.getPermissions().size();
2617 public FileHeader expandFile(FileHeader folder) throws ObjectNotFoundException{
2618 FileHeader result = dao.getEntityById(FileHeader.class, folder.getId());
2620 result.getPermissions().size();
2621 result.getFileTags().size();
2626 public Group expandGroup(Group folder) throws ObjectNotFoundException{
2627 Group result = dao.getEntityById(Group.class, folder.getId());
2628 result.getMembers().size();