2 * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd.
4 * This file is part of GSS.
6 * GSS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GSS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GSS. If not, see <http://www.gnu.org/licenses/>.
19 package gr.ebs.gss.server.ejb;
21 import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
23 import gr.ebs.gss.admin.client.ui.UsersTable;
24 import gr.ebs.gss.client.exceptions.DuplicateNameException;
25 import gr.ebs.gss.client.exceptions.GSSIOException;
26 import gr.ebs.gss.client.exceptions.InsufficientPermissionsException;
27 import gr.ebs.gss.client.exceptions.InvitationUsedException;
28 import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
29 import gr.ebs.gss.client.exceptions.QuotaExceededException;
30 import gr.ebs.gss.server.domain.AuditInfo;
31 import gr.ebs.gss.server.domain.FileBody;
32 import gr.ebs.gss.server.domain.FileHeader;
33 import gr.ebs.gss.server.domain.FileTag;
34 import gr.ebs.gss.server.domain.FileUploadStatus;
35 import gr.ebs.gss.server.domain.Folder;
36 import gr.ebs.gss.server.domain.Group;
37 import gr.ebs.gss.server.domain.FileLock;
38 import gr.ebs.gss.server.domain.Invitation;
39 import gr.ebs.gss.server.domain.Nonce;
40 import gr.ebs.gss.server.domain.Permission;
41 import gr.ebs.gss.server.domain.User;
42 import gr.ebs.gss.server.domain.UserClass;
43 import gr.ebs.gss.server.domain.UserLogin;
44 import gr.ebs.gss.server.domain.WebDavNonce;
45 import gr.ebs.gss.server.domain.dto.StatsDTO;
46 import gr.ebs.gss.server.domain.dto.UserDTO;
49 import java.io.FileInputStream;
50 import java.io.FileNotFoundException;
51 import java.io.FileOutputStream;
52 import java.io.IOException;
53 import java.io.InputStream;
54 import java.io.UnsupportedEncodingException;
55 import java.net.MalformedURLException;
56 import java.util.ArrayList;
57 import java.util.Date;
58 import java.util.Iterator;
59 import java.util.LinkedHashSet;
60 import java.util.List;
61 import java.util.Locale;
62 import java.util.Random;
64 import java.util.StringTokenizer;
67 import javax.ejb.EJBException;
68 import javax.ejb.EJBTransactionRolledbackException;
69 import javax.ejb.Stateless;
70 import javax.ejb.TransactionAttribute;
71 import javax.ejb.TransactionAttributeType;
72 import javax.jms.Connection;
73 import javax.jms.ConnectionFactory;
74 import javax.jms.JMSException;
75 import javax.jms.MapMessage;
76 import javax.jms.MessageProducer;
77 import javax.jms.Queue;
78 import javax.jms.QueueConnectionFactory;
79 import javax.jms.Session;
80 import javax.naming.Context;
81 import javax.naming.InitialContext;
82 import javax.naming.NamingException;
83 import javax.persistence.PersistenceException;
85 import org.apache.commons.lang.StringUtils;
86 import org.apache.commons.logging.Log;
87 import org.apache.commons.logging.LogFactory;
88 import org.apache.solr.client.solrj.SolrQuery;
89 import org.apache.solr.client.solrj.SolrResponse;
90 import org.apache.solr.client.solrj.SolrServerException;
91 import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
92 import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
93 import org.apache.solr.client.solrj.response.QueryResponse;
94 import org.apache.solr.common.SolrDocument;
95 import org.apache.solr.common.SolrDocumentList;
96 import org.apache.solr.common.SolrException;
97 import org.apache.solr.common.SolrInputDocument;
98 import org.hibernate.exception.ConstraintViolationException;
100 import com.novell.ldap.LDAPAttribute;
101 import com.novell.ldap.LDAPAttributeSet;
102 import com.novell.ldap.LDAPConnection;
103 import com.novell.ldap.LDAPEntry;
104 import com.novell.ldap.LDAPException;
107 * The concrete implementation of the ExternalAPI interface.
112 public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
114 * The default MIME type for files without an explicit one.
116 private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
119 * The size of the buffer that is used to temporarily store chunks of
120 * uploaded files, while storing them to the file repository.
122 private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
127 private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
130 * Injected reference to the GSSDAO data access facade.
137 * A cached random number generator for creating unique filenames.
139 private static Random random = new Random();
142 * Mark the folder and all of its parent folders as modified from the specified user.
144 private void touchParentFolders(Folder folder, User user, Date date) {
147 AuditInfo ai = f.getAuditInfo();
148 ai.setModifiedBy(user);
149 ai.setModificationDate(date);
155 private Long getRootFolderId(Long userId) throws ObjectNotFoundException {
157 throw new ObjectNotFoundException("No user specified");
158 return dao.getRootFolderId(userId);
162 public Folder getRootFolder(Long userId) throws ObjectNotFoundException {
164 throw new ObjectNotFoundException("No user specified");
165 Folder folder = dao.getRootFolder(userId);
170 public Folder getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
172 throw new ObjectNotFoundException("No user specified");
173 if (folderId == null)
174 throw new ObjectNotFoundException("No folder specified");
175 final User user = dao.getEntityById(User.class, userId);
176 final Folder folder = dao.getEntityById(Folder.class, folderId);
178 if (!folder.hasReadPermission(user))
179 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
180 return expandFolder(folder);
184 public User getUser(Long userId) throws ObjectNotFoundException {
186 throw new ObjectNotFoundException("No user specified");
187 return dao.getEntityById(User.class, userId);
191 public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
192 return getUser(userId).getDTO();
196 public Group getGroup(final Long groupId) throws ObjectNotFoundException {
198 throw new ObjectNotFoundException("No group specified");
199 final Group group = dao.getEntityById(Group.class, groupId);
204 public Group getGroup(Long userId, String name) throws ObjectNotFoundException {
206 throw new ObjectNotFoundException("No user specified");
208 throw new ObjectNotFoundException("No group specified");
209 User user = dao.getEntityById(User.class, userId);
210 List<Group> groups = user.getGroupsSpecified();
211 for (Group group: groups)
212 if (group.getName().equals(name))
214 throw new ObjectNotFoundException("Group " + name + " not found");
218 public List<Group> getGroups(final Long userId) throws ObjectNotFoundException {
220 throw new ObjectNotFoundException("No user specified");
221 final List<Group> groups = dao.getGroups(userId);
226 public List<FileHeader> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
227 throws ObjectNotFoundException, InsufficientPermissionsException {
230 throw new ObjectNotFoundException("No user specified");
231 if (folderId == null)
232 throw new ObjectNotFoundException("No folder specified");
233 User user = dao.getEntityById(User.class, userId);
234 Folder folder = dao.getEntityById(Folder.class, folderId);
235 if (!folder.hasReadPermission(user))
236 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
237 List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
242 public List<User> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
245 throw new ObjectNotFoundException("No user specified");
247 throw new ObjectNotFoundException("No group specified");
249 // Do the actual work.
250 final List<User> users = dao.getUsers(groupId);
255 public Folder createFolder(Long userId, Long parentId, String name)
256 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
259 throw new ObjectNotFoundException("No user specified");
260 if (StringUtils.isEmpty(name))
261 throw new ObjectNotFoundException("New folder name is empty");
262 if (parentId == null)
263 throw new ObjectNotFoundException("No parent specified");
264 if (dao.existsFolderOrFile(parentId, name))
265 throw new DuplicateNameException("A folder or file with the name '" +
266 name + "' already exists at this level");
268 User creator = dao.getEntityById(User.class, userId);
270 Folder parent = null;
272 parent = dao.getEntityById(Folder.class, parentId);
273 } catch (ObjectNotFoundException onfe) {
274 // Supply a more accurate problem description.
275 throw new ObjectNotFoundException("Parent folder not found");
277 if (!parent.hasWritePermission(creator))
278 throw new InsufficientPermissionsException("You don't have the permissions" +
279 " to write to this folder");
281 // Do the actual work.
282 return createFolder(name, parent, creator);
286 * Create a new folder with the provided name, parent and owner.
291 * @return the new folder
293 private Folder createFolder(String name, Folder parent, User creator) {
294 Folder folder = new Folder();
295 folder.setName(name);
296 if (parent != null) {
297 parent.addSubfolder(folder);
298 folder.setOwner(parent.getOwner());
300 folder.setOwner(creator);
302 Date now = new Date();
303 AuditInfo auditInfo = new AuditInfo();
304 auditInfo.setCreatedBy(creator);
305 auditInfo.setCreationDate(now);
306 auditInfo.setModifiedBy(creator);
307 auditInfo.setModificationDate(now);
308 folder.setAuditInfo(auditInfo);
309 touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
312 for (Permission p : parent.getPermissions()) {
313 Permission permission = new Permission();
314 permission.setGroup(p.getGroup());
315 permission.setUser(p.getUser());
316 permission.setRead(p.getRead());
317 permission.setWrite(p.getWrite());
318 permission.setModifyACL(p.getModifyACL());
319 folder.addPermission(permission);
322 Permission permission = new Permission();
323 permission.setUser(creator);
324 permission.setRead(true);
325 permission.setWrite(true);
326 permission.setModifyACL(true);
327 folder.addPermission(permission);
331 folder.setReadForAll(parent.isReadForAll());
338 public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
341 throw new ObjectNotFoundException("No user specified");
342 if (folderId == null)
343 throw new ObjectNotFoundException("No folder specified");
345 // Do the actual work.
346 final Folder folder = dao.getEntityById(Folder.class, folderId);
347 final Folder parent = folder.getParent();
349 throw new ObjectNotFoundException("Deleting the root folder is not allowed");
350 final User user = dao.getEntityById(User.class, userId);
351 if (!folder.hasDeletePermission(user)) {
352 logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
353 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
355 removeSubfolderFiles(folder);
356 parent.removeSubfolder(folder);
358 touchParentFolders(parent, user, new Date());
362 * Traverses the folder and deletes all actual files (file system)
363 * regardless of permissions
367 private void removeSubfolderFiles(Folder folder) {
368 //remove files for all subfolders
369 for (Folder subfolder:folder.getSubfolders())
370 removeSubfolderFiles(subfolder);
371 //remove this folder's file bodies (actual files)
372 for (FileHeader file:folder.getFiles()) {
373 for (FileBody body:file.getBodies())
374 deleteActualFile(body.getStoredFilePath());
375 indexFile(file.getId(), true);
380 @SuppressWarnings("unchecked")
381 public List<Folder> getSubfolders(Long userId, Long folderId)
382 throws ObjectNotFoundException, InsufficientPermissionsException {
384 throw new ObjectNotFoundException("No user specified");
385 if (folderId == null)
386 throw new ObjectNotFoundException("No folder specified");
387 User user = dao.getEntityById(User.class, userId);
388 Folder folder = dao.getEntityById(Folder.class, folderId);
389 if (!folder.hasReadPermission(user))
390 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
391 List<Folder> result = new ArrayList<Folder>();
392 if (folder.hasReadPermission(user))
393 for (Folder f : folder.getSubfolders())
394 if (f.hasReadPermission(user) && !f.isDeleted())
400 public Folder updateFolder(Long userId, Long folderId, String folderName,
402 Set<Permission> permissions)
403 throws InsufficientPermissionsException, ObjectNotFoundException,
404 DuplicateNameException {
408 throw new ObjectNotFoundException("No user specified");
409 if (folderId == null)
410 throw new ObjectNotFoundException("No folder specified");
412 Folder folder = dao.getEntityById(Folder.class, folderId);
413 User user = dao.getEntityById(User.class, userId);
414 if (folderName != null && !folder.hasWritePermission(user))
415 throw new InsufficientPermissionsException("You don't have the necessary permissions");
416 if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
417 throw new InsufficientPermissionsException("You don't have the necessary permissions");
418 // Check permissions for making file public.
419 if (readForAll != null && !user.equals(folder.getOwner()))
420 throw new InsufficientPermissionsException("Only the owner can make a folder public or not public");
422 Folder parent = folder.getParent();
423 if (folderName != null) {
425 if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
426 throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
428 // Do the actual modification.
429 folder.setName(folderName);
431 if (permissions != null)
432 setFolderPermissions(user, folder, permissions);
433 if (readForAll != null)
434 setFolderReadForAll(user, folder, readForAll);
435 folder.getAuditInfo().setModificationDate(new Date());
436 folder.getAuditInfo().setModifiedBy(user);
438 touchParentFolders(folder, user, new Date());
439 // Re-index the folder contents if it was modified.
440 if ((permissions != null && !permissions.isEmpty()) || readForAll != null) {
447 private void indexFolder(Folder folder) {
448 for (FileHeader fh : folder.getFiles())
449 indexFile(fh.getId(), false);
450 for (Folder f : folder.getSubfolders())
455 public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
458 throw new ObjectNotFoundException("No user specified");
459 if (StringUtils.isEmpty(name))
460 throw new ObjectNotFoundException("New group name is empty");
461 if (name.indexOf('/')>=0)
462 throw new IllegalArgumentException("Character '/' is not allowed in group name");
463 if (dao.existsGroup(userId, name))
464 throw new DuplicateNameException("A group with the name '" + name + "' already exists");
466 // TODO: Check permissions
468 final User owner = dao.getEntityById(User.class, userId);
470 // Do the actual work.
471 owner.createGroup(name);
475 public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
478 throw new ObjectNotFoundException("No user specified");
480 throw new ObjectNotFoundException("No group specified");
482 // Do the actual work.
483 final User owner = dao.getEntityById(User.class, userId);
484 final Group group = dao.getEntityById(Group.class, groupId);
485 final Date now = new Date();
486 // Only delete the group if actually owned by the user.
487 if (group.getOwner().equals(owner)) {
488 List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
489 for (Folder f : folders){
490 f.getPermissions().removeAll(group.getPermissions());
491 for(FileHeader file : f.getFiles()){
492 file.getPermissions().removeAll(group.getPermissions());
495 List<FileHeader> files = dao.getFilesPermittedForGroup(userId, groupId);
496 for(FileHeader h : files){
497 h.getPermissions().removeAll(group.getPermissions());
499 owner.removeSpecifiedGroup(group);
502 else throw new InsufficientPermissionsException("You are not the owner of this group");
506 public FileHeader createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
507 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
508 InsufficientPermissionsException, QuotaExceededException {
511 file = uploadFile(stream, userId);
512 } catch ( IOException ioe) {
513 // Supply a more accurate problem description.
514 throw new GSSIOException("Problem creating file",ioe);
519 } catch (IOException e) {
520 logger.error("Unable to close InputStream on FileUpload:",e);
523 return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
526 private void indexFile(Long fileId, boolean delete) {
527 Connection qConn = null;
528 Session session = null;
529 MessageProducer sender = null;
531 Context jndiCtx = new InitialContext();
532 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
533 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
534 qConn = factory.createConnection();
535 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
536 sender = session.createProducer(queue);
538 MapMessage map = session.createMapMessage();
539 map.setObject("id", fileId);
540 map.setBoolean("delete", delete);
543 catch (NamingException e) {
544 logger.error("Index was not updated: ", e);
546 catch (JMSException e) {
547 logger.error("Index was not updated: ", e);
558 catch (JMSException e) {
567 * A helper method that generates a unique file path for a stored file. The
568 * files are stored using random hash names that are distributed evenly in
569 * a 2-level tree of subdirectories named after the first two hex characters
570 * in the name. For example, file ab1234cd5769f will be stored in the path
571 * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
572 * if they don't already exist.
574 * @return a unique new file path
576 private String generateRepositoryFilePath() {
577 String filename = Long.toHexString(random.nextLong());
578 String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
579 File root = new File(fileRepositoryPath);
582 File firstFolder = new File(root + File.separator + filename.substring(0, 1));
583 if (!firstFolder.exists())
585 File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
586 if (!secondFolder.exists())
587 secondFolder.mkdir();
588 return secondFolder + File.separator + filename;
592 public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
595 throw new ObjectNotFoundException("No user specified");
597 throw new ObjectNotFoundException("No file specified");
599 // Do the actual work.
600 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
601 final Folder parent = file.getFolder();
603 throw new ObjectNotFoundException("The specified file has no parent folder");
604 final User user = dao.getEntityById(User.class, userId);
605 if (!file.hasDeletePermission(user))
606 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
607 for (final FileBody body : file.getBodies())
608 deleteActualFile(body.getStoredFilePath());
610 touchParentFolders(parent, user, new Date());
611 indexFile(fileId, true);
615 public void deleteActualFile(String path) {
618 File file = new File(path);
620 logger.error("Could not delete file " + path + " "+file.exists());
624 public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
626 throw new ObjectNotFoundException("No user specified");
627 if (fileHeaderId == null)
628 throw new ObjectNotFoundException("No file specified");
629 if (StringUtils.isEmpty(tag))
630 throw new ObjectNotFoundException("Tag is empty");
632 final User user = dao.getEntityById(User.class, userId);
633 final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
634 final Folder parent = fh.getFolder();
636 throw new ObjectNotFoundException("The specified file has no parent folder");
637 user.addTag(fh, tag);
638 touchParentFolders(parent, user, new Date());
642 public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
643 return dao.getUserTags(userId);
647 public void updateFile(Long userId, Long fileId, String name,
648 String tagSet, Date modificationDate, Boolean versioned,
649 Boolean readForAll, Set<Permission> permissions)
650 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
652 throw new ObjectNotFoundException("No user specified");
654 throw new ObjectNotFoundException("No file specified");
655 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
656 final Folder parent = file.getFolder();
658 throw new ObjectNotFoundException("The specified file has no parent folder");
660 User user = dao.getEntityById(User.class, userId);
661 // Check permissions for modifying the file metadata.
662 if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
663 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
664 // Check permissions for making file public.
665 if (readForAll != null && !user.equals(file.getOwner()))
666 throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
667 // Check permissions for modifying the ACL.
668 if(permissions != null && !permissions.isEmpty() && !file.hasModifyACLPermission(user))
669 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update the permissions on file " + file.getName() + "(" + file.getId() + ")");
672 // Do plain check for file already exists.
673 // Extreme concurrency case should be caught by constraint violation later.
674 if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
678 if (modificationDate != null)
679 file.getAuditInfo().setModificationDate(modificationDate);
681 file.getAuditInfo().setModificationDate(new Date());
682 file.getAuditInfo().setModifiedBy(user);
684 List<FileTag> tags = file.getFileTags();
685 if (tagSet != null) {
686 Iterator<FileTag> i = tags.iterator();
687 while (i.hasNext()) {
688 FileTag tag = i.next();
695 StringTokenizer st = new StringTokenizer(tagSet, ",");
696 while (st.hasMoreTokens())
697 new FileTag(user, file, st.nextToken().trim());
699 if (versioned != null && !file.isVersioned() == versioned) {
700 if (file.isVersioned())
701 removeOldVersions(userId, fileId);
702 file.setVersioned(versioned);
704 if (readForAll != null && user.equals(file.getOwner()))
705 file.setReadForAll(readForAll);
706 if (permissions != null && !permissions.isEmpty())
707 setFilePermissions(file, permissions);
710 * Force constraint violation to manifest itself here.
711 * This should cover extreme concurrency cases that the simple check
712 * above hasn't caught.
717 catch (EJBTransactionRolledbackException e) {
718 Throwable cause = e.getCause();
719 if (cause instanceof PersistenceException && cause.getCause() instanceof ConstraintViolationException)
720 throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
724 touchParentFolders(parent, user, new Date());
726 // Re-index the file if it was modified.
727 if (name != null || tagSet != null || (permissions != null && !permissions.isEmpty()) || readForAll != null)
728 indexFile(fileId, false);
732 public InputStream getFileContents(Long userId, Long fileId)
733 throws ObjectNotFoundException, InsufficientPermissionsException {
735 throw new ObjectNotFoundException("No user specified");
737 throw new ObjectNotFoundException("No file specified");
739 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
740 User user = dao.getEntityById(User.class, userId);
741 if (!header.hasReadPermission(user)) {
742 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
743 throw new InsufficientPermissionsException("You don't have the necessary permissions");
746 File f = new File(header.getCurrentBody().getStoredFilePath());
748 return new FileInputStream(f);
749 } catch (FileNotFoundException e) {
750 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
751 throw new ObjectNotFoundException("The file contents could not be located");
756 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
759 public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
761 throw new ObjectNotFoundException("No user specified");
763 throw new ObjectNotFoundException("No file specified");
765 throw new ObjectNotFoundException("No file specified");
767 final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
768 final FileBody body = dao.getEntityById(FileBody.class, bodyId);
769 final User user = dao.getEntityById(User.class, userId);
770 if (!header.hasReadPermission(user)) {
771 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
772 throw new InsufficientPermissionsException("You don't have the necessary permissions");
775 File f = new File(body.getStoredFilePath());
777 return new FileInputStream(f);
778 } catch (FileNotFoundException e) {
779 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
780 throw new ObjectNotFoundException("The file contents could not be located");
785 public FileHeader getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
787 throw new ObjectNotFoundException("No user specified");
789 throw new ObjectNotFoundException("No file specified");
790 final User user = dao.getEntityById(User.class, userId);
791 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
792 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
793 throw new InsufficientPermissionsException("You don't have the necessary permissions");
798 public FileBody getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
800 throw new ObjectNotFoundException("No user specified");
802 throw new ObjectNotFoundException("No file specified");
803 User user = dao.getEntityById(User.class, userId);
804 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
805 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
806 throw new InsufficientPermissionsException("You don't have the necessary permissions");
807 FileBody body = dao.getEntityById(FileBody.class, bodyId);
812 public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
813 throws ObjectNotFoundException {
815 throw new ObjectNotFoundException("No user specified");
816 if (StringUtils.isEmpty(path))
817 throw new ObjectNotFoundException("No path specified");
819 User owner = dao.getEntityById(User.class, ownerId);
820 List<String> pathElements = new ArrayList<String>();
821 StringTokenizer st = new StringTokenizer(path, "/");
822 while (st.hasMoreTokens())
823 pathElements.add(st.nextToken());
824 if (pathElements.size() < 1)
825 return getRootFolder(owner.getId());
826 // Store the last element, since it requires special handling.
827 String lastElement = pathElements.remove(pathElements.size() - 1);
829 Folder cursor = null;
830 Long rootFolderId = getRootFolderId(owner.getId());
831 // Traverse and verify the specified folder path.
832 for (String pathElement : pathElements) {
833 cursor = getFolder(cursor==null ? rootFolderId : cursor.getId(), pathElement);
834 if (cursor.isDeleted())
835 throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
838 // Use the lastElement to retrieve the actual resource.
839 Object resource = null;
841 FileHeader file = getFile(cursor==null ? rootFolderId : cursor.getId(), lastElement);
842 if (ignoreDeleted && file.isDeleted())
843 throw new ObjectNotFoundException("Resource not found");
845 } catch (ObjectNotFoundException e) {
846 // Perhaps the requested resource is not a file, so
847 // check for folders as well.
848 Folder folder = getFolder(cursor==null ? rootFolderId : cursor.getId(), lastElement);
849 if (ignoreDeleted && folder.isDeleted())
850 throw new ObjectNotFoundException("Resource not found");
857 * Retrieve a file for the specified user that has the specified name and
858 * its parent folder has id equal to folderId.
860 * @param folderId the ID of the parent folder
861 * @param name the name of the requested file
862 * @return the file found
863 * @throws ObjectNotFoundException if the specified folder or file was not
864 * found, with the exception message mentioning the precise
867 private FileHeader getFile(Long folderId, String name) throws ObjectNotFoundException {
868 if (folderId == null)
869 throw new ObjectNotFoundException("No parent folder specified");
870 if (StringUtils.isEmpty(name))
871 throw new ObjectNotFoundException("No file specified");
873 FileHeader file = dao.getFile(folderId, name);
878 * Retrieve a folder for the specified user that has the specified name and
879 * its parent folder has id equal to parentId.
881 * @param parentId the ID of the parent folder
882 * @param name the name of the requested folder
883 * @return the folder found
884 * @throws ObjectNotFoundException if the specified folder or parent was not
885 * found, with the exception message mentioning the precise
888 private Folder getFolder(Long parentId, String name) throws ObjectNotFoundException {
889 if (parentId == null)
890 throw new ObjectNotFoundException("No parent folder specified");
891 if (StringUtils.isEmpty(name))
892 throw new ObjectNotFoundException("No folder specified");
894 Folder folder = dao.getFolder(parentId, name);
898 private FileHeader updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
901 file = uploadFile(resourceInputStream, userId);
902 } catch ( IOException ioe) {
903 // Supply a more accurate problem description.
904 throw new GSSIOException("Problem creating file",ioe);
906 return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
910 public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
912 throw new ObjectNotFoundException("No user specified");
914 throw new ObjectNotFoundException("No file specified");
915 if (StringUtils.isEmpty(dest))
916 throw new ObjectNotFoundException("No destination specified");
918 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
919 if (!(destination instanceof Folder))
920 throw new ObjectNotFoundException("Destination parent folder not found");
921 Folder parent = (Folder) destination;
922 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
926 public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
928 throw new ObjectNotFoundException("No user specified");
930 throw new ObjectNotFoundException("No owner specified");
932 throw new ObjectNotFoundException("No file specified");
933 if (StringUtils.isEmpty(dest))
934 throw new ObjectNotFoundException("No destination specified");
936 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
937 if (!(destination instanceof Folder))
938 throw new ObjectNotFoundException("Destination parent folder not found");
939 Folder parent = (Folder) destination;
940 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
944 public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
946 throw new ObjectNotFoundException("No user specified");
948 throw new ObjectNotFoundException("No file specified");
950 throw new ObjectNotFoundException("No destination specified");
951 if (StringUtils.isEmpty(destName))
952 throw new ObjectNotFoundException("No destination file name specified");
954 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
955 Folder destination = dao.getEntityById(Folder.class, destId);
956 User user = dao.getEntityById(User.class, userId);
957 if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
958 throw new InsufficientPermissionsException("You don't have the necessary permissions");
959 boolean versioned = file.isVersioned();
960 int versionsNumber = file.getBodies().size();
961 FileBody oldestBody = file.getBodies().get(0);
962 assert oldestBody != null;
963 File contents = new File(oldestBody.getStoredFilePath());
965 createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
966 FileHeader copiedFile = dao.getFile(destination.getId(), destName);
967 copiedFile.setVersioned(versioned);
969 if (versionsNumber > 1)
970 for (int i = 1; i < versionsNumber; i++) {
971 FileBody body = file.getBodies().get(i);
973 contents = new File(body.getStoredFilePath());
974 updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
976 List<FileTag> tags = file.getFileTags();
977 for (FileTag tag : tags)
978 createTag(userId, copiedFile.getId(), tag.getTag());
980 } catch (FileNotFoundException e) {
981 throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
987 public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
989 throw new ObjectNotFoundException("No user specified");
990 if (folderId == null)
991 throw new ObjectNotFoundException("No folder specified");
992 if (StringUtils.isEmpty(dest))
993 throw new ObjectNotFoundException("No destination specified");
995 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
996 if (!(destination instanceof Folder))
997 throw new ObjectNotFoundException("Destination folder not found");
998 Folder parent = (Folder) destination;
999 copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
1003 public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1005 throw new ObjectNotFoundException("No user specified");
1006 if (folderId == null)
1007 throw new ObjectNotFoundException("No folder specified");
1009 throw new ObjectNotFoundException("No destination specified");
1010 if (StringUtils.isEmpty(destName))
1011 throw new ObjectNotFoundException("No destination folder name specified");
1012 Folder folder = dao.getEntityById(Folder.class, folderId);
1013 Folder destination = dao.getEntityById(Folder.class, destId);
1014 User user = dao.getEntityById(User.class, userId);
1015 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1016 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1017 createFolder(user.getId(), destination.getId(), destName);
1021 public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1023 throw new ObjectNotFoundException("No user specified");
1024 if (ownerId == null)
1025 throw new ObjectNotFoundException("No owner specified");
1026 if (folderId == null)
1027 throw new ObjectNotFoundException("No folder specified");
1028 if (StringUtils.isEmpty(dest))
1029 throw new ObjectNotFoundException("No destination specified");
1031 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1032 if (!(destination instanceof Folder))
1033 throw new ObjectNotFoundException("Destination folder not found");
1034 Folder parent = (Folder) destination;
1035 copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1039 public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1041 throw new ObjectNotFoundException("No user specified");
1042 if (folderId == null)
1043 throw new ObjectNotFoundException("No folder specified");
1045 throw new ObjectNotFoundException("No destination specified");
1046 if (StringUtils.isEmpty(destName))
1047 throw new ObjectNotFoundException("No destination folder name specified");
1049 Folder folder = dao.getEntityById(Folder.class, folderId);
1050 Folder destination = dao.getEntityById(Folder.class, destId);
1051 final User user = dao.getEntityById(User.class, userId);
1052 // XXX: quick fix need to copy only visible items to user (Source
1054 if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1056 if(folder.isDeleted())//do not copy trashed folder and contents
1058 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1059 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1060 createFolder(user.getId(), destination.getId(), destName);
1061 Folder createdFolder = dao.getFolder(destination.getId(), destName);
1062 List<FileHeader> files = folder.getFiles();
1064 for (FileHeader file : files)
1065 if(!file.isDeleted())
1066 copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1067 List<Folder> subFolders = folder.getSubfolders();
1068 if (subFolders != null)
1069 for (Folder sub : subFolders)
1070 if(!sub.getId().equals(createdFolder.getId()))
1071 copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1076 * For a provided path, remove the last element and return the rest, that is
1077 * the path of the parent folder.
1079 * @param path the specified path
1080 * @return the path of the parent folder
1081 * @throws ObjectNotFoundException if the provided string contains no path
1084 private String getParentPath(String path) throws ObjectNotFoundException {
1085 int lastDelimiter = path.lastIndexOf('/');
1086 if (lastDelimiter == 0)
1088 if (lastDelimiter == -1)
1090 throw new ObjectNotFoundException("There is no parent in the path: " + path);
1091 else if (lastDelimiter < path.length() - 1)
1092 // Return the part before the delimiter.
1093 return path.substring(0, lastDelimiter);
1095 // Remove the trailing delimiter and then recurse.
1096 String strippedTrail = path.substring(0, lastDelimiter);
1097 return getParentPath(strippedTrail);
1102 * Get the last element in a path that denotes the file or folder name.
1104 * @param path the provided path
1105 * @return the last element in the path
1107 private String getLastElement(String path) {
1108 int lastDelimiter = path.lastIndexOf('/');
1109 if (lastDelimiter == -1)
1112 else if (lastDelimiter < path.length() - 1)
1113 // Return the part after the delimiter.
1114 return path.substring(lastDelimiter + 1);
1116 // Remove the trailing delimiter and then recurse.
1117 String strippedTrail = path.substring(0, lastDelimiter);
1118 return getLastElement(strippedTrail);
1123 public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1125 throw new ObjectNotFoundException("No user specified");
1127 throw new ObjectNotFoundException("No file specified");
1129 // Do the actual work.
1130 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1131 Folder parent = file.getFolder();
1133 throw new ObjectNotFoundException("The specified file has no parent folder");
1134 User user = dao.getEntityById(User.class, userId);
1135 trashFile(user, file);
1136 touchParentFolders(parent, user, new Date());
1139 private void trashFile(User user, FileHeader file) throws InsufficientPermissionsException {
1140 if (!file.hasDeletePermission(user))
1141 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1143 file.setDeleted(true);
1147 public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1149 throw new ObjectNotFoundException("No user specified");
1150 if (ownerId == null)
1151 throw new ObjectNotFoundException("No owner specified");
1153 throw new ObjectNotFoundException("No file specified");
1154 if (StringUtils.isEmpty(dest))
1155 throw new ObjectNotFoundException("No destination specified");
1157 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1158 if (!(destination instanceof Folder))
1159 throw new ObjectNotFoundException("Destination parent folder not found");
1160 Folder parent = (Folder) destination;
1161 moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1165 public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1167 throw new ObjectNotFoundException("No user specified");
1169 throw new ObjectNotFoundException("No file specified");
1171 throw new ObjectNotFoundException("No destination specified");
1172 if (StringUtils.isEmpty(destName))
1173 throw new ObjectNotFoundException("No destination file name specified");
1175 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1176 Folder source = file.getFolder();
1177 Folder destination = dao.getEntityById(Folder.class, destId);
1179 User owner = dao.getEntityById(User.class, userId);
1180 if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1181 throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1183 // if the destination folder belongs to another user:
1184 if (!file.getOwner().equals(destination.getOwner())) {
1185 // (a) check if the destination quota allows the move
1186 if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1187 throw new QuotaExceededException("Not enough free space available");
1188 User newOwner = destination.getOwner();
1189 // (b) if quota OK, change the owner of the file
1190 file.setOwner(newOwner);
1191 // if the file has no permission for the new owner, add it
1192 Permission ownerPermission = null;
1193 for (final Permission p : file.getPermissions())
1194 if (p.getUser() != null)
1195 if (p.getUser().equals(newOwner)) {
1196 ownerPermission = p;
1199 if (ownerPermission == null) {
1200 ownerPermission = new Permission();
1201 ownerPermission.setUser(newOwner);
1202 file.addPermission(ownerPermission);
1204 ownerPermission.setRead(true);
1205 ownerPermission.setWrite(true);
1206 ownerPermission.setModifyACL(true);
1208 // move the file to the destination folder
1209 file.setFolder(destination);
1210 touchParentFolders(source, owner, new Date());
1211 touchParentFolders(destination, owner, new Date());
1215 public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1217 throw new ObjectNotFoundException("No user specified");
1218 if (ownerId == null)
1219 throw new ObjectNotFoundException("No owner specified");
1220 if (folderId == null)
1221 throw new ObjectNotFoundException("No folder specified");
1222 if (StringUtils.isEmpty(dest))
1223 throw new ObjectNotFoundException("No destination specified");
1225 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1226 if (!(destination instanceof Folder))
1227 throw new ObjectNotFoundException("Destination parent folder not found");
1228 Folder parent = (Folder) destination;
1229 moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1233 public void moveFolder(Long userId, Long folderId, Long destId, String destName)
1234 throws ObjectNotFoundException, InsufficientPermissionsException,
1235 QuotaExceededException {
1236 Folder source = dao.getEntityById(Folder.class, folderId);
1237 Folder destination = dao.getEntityById(Folder.class, destId);
1238 User user = dao.getEntityById(User.class, userId);
1239 User sourceOwner = source.getOwner();
1240 User destinationOwner = destination.getOwner();
1241 // Do not move trashed folders and contents.
1242 if (source.isDeleted())
1244 // Check permissions.
1245 if (!destination.hasWritePermission(user)
1246 || !source.hasReadPermission(user)
1247 || !source.hasWritePermission(user))
1248 throw new InsufficientPermissionsException("You don't have the " +
1249 "necessary permissions");
1250 // Use the same timestamp for all subsequent modifications to make
1251 // changes appear simultaneous.
1252 Date now = new Date();
1253 // If source and destination are not in the same user's namespace,
1254 // change owners and check quota.
1255 if (!sourceOwner.equals(destinationOwner)) {
1256 changeOwner(source, destinationOwner, user, now);
1257 if (getQuotaLeft(destinationOwner.getId()) < 0)
1258 throw new QuotaExceededException("Not enough free space " +
1259 "available in destination folder");
1261 // Perform the move.
1262 Folder oldParent = source.getParent();
1263 oldParent.removeSubfolder(source);
1264 destination.addSubfolder(source);
1265 // Mark the former parent and destination trees upwards as modified.
1266 touchParentFolders(oldParent, user, now);
1267 touchParentFolders(source, user, now);
1271 * Recursively change the owner of the specified folder and all of its
1272 * contents to the specified owner. Also mark them all as modified with the
1273 * specified modifier and modificationDate.
1275 private void changeOwner(Folder folder, User owner, User modifier, Date modificationDate) {
1276 for (FileHeader file: folder.getFiles()) {
1277 file.setOwner(owner);
1278 file.getAuditInfo().setModificationDate(modificationDate);
1279 file.getAuditInfo().setModifiedBy(modifier);
1281 for (Folder sub: folder.getSubfolders())
1282 changeOwner(sub, owner, modifier, modificationDate);
1283 folder.setOwner(owner);
1284 folder.getAuditInfo().setModificationDate(modificationDate);
1285 folder.getAuditInfo().setModifiedBy(modifier);
1289 public List<FileHeader> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1292 throw new ObjectNotFoundException("No user specified");
1294 // Do the actual work.
1295 final List<FileHeader> files = dao.getDeletedFiles(userId);
1300 public void removeFileFromTrash(Long userId, Long fileId)
1301 throws ObjectNotFoundException, InsufficientPermissionsException {
1303 throw new ObjectNotFoundException("No user specified");
1305 throw new ObjectNotFoundException("No file specified");
1307 // Do the actual work.
1308 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1309 Folder parent = file.getFolder();
1311 throw new ObjectNotFoundException("The specified file has no parent folder");
1312 User user = dao.getEntityById(User.class, userId);
1313 untrashFile(user, file);
1314 touchParentFolders(parent, user, new Date());
1317 private void untrashFile(User user, FileHeader file) throws InsufficientPermissionsException {
1318 if (!file.hasDeletePermission(user))
1319 throw new InsufficientPermissionsException("User " + user.getUsername() +
1320 " cannot restore file " + file.getName());
1322 file.setDeleted(false);
1326 public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1328 throw new ObjectNotFoundException("No user specified");
1329 if (folderId == null)
1330 throw new ObjectNotFoundException("No folder specified");
1331 Folder folder = dao.getEntityById(Folder.class, folderId);
1332 User user = dao.getEntityById(User.class, userId);
1333 trashFolder(user, folder);
1334 touchParentFolders(folder, user, new Date());
1337 private void trashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException {
1338 if (!folder.hasDeletePermission(user))
1339 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1340 folder.setDeleted(true);
1341 for (FileHeader file : folder.getFiles())
1342 trashFile(user, file);
1343 for (Folder subFolder : folder.getSubfolders())
1344 trashFolder(user, subFolder);
1348 public void removeFolderFromTrash(Long userId, Long folderId)
1349 throws ObjectNotFoundException, InsufficientPermissionsException {
1351 throw new ObjectNotFoundException("No user specified");
1352 if (folderId == null)
1353 throw new ObjectNotFoundException("No folder specified");
1354 Folder folder = dao.getEntityById(Folder.class, folderId);
1355 User user = dao.getEntityById(User.class, userId);
1356 untrashFolder(user, folder);
1357 touchParentFolders(folder, user, new Date());
1360 private void untrashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException {
1361 if (!folder.hasDeletePermission(user))
1362 throw new InsufficientPermissionsException("User " + user.getUsername() +
1363 " cannot restore folder " + folder.getName());
1364 folder.setDeleted(false);
1365 for (FileHeader file : folder.getFiles())
1366 untrashFile(user, file);
1367 for (Folder subFolder : folder.getSubfolders())
1368 untrashFolder(user, subFolder);
1372 public List<Folder> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1373 List<Folder> folders = dao.getDeletedRootFolders(userId);
1378 public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1379 List<Folder> deletedRootFolders = getDeletedRootFolders(userId);
1380 for (Folder folder : deletedRootFolders)
1381 deleteFolder(userId, folder.getId());
1382 List<FileHeader> deletedFiles = getDeletedFiles(userId);
1383 for (FileHeader file : deletedFiles)
1384 deleteFile(userId, file.getId());
1388 public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1389 List<Folder> deletedRootFolders = getDeletedRootFolders(userId);
1390 for (Folder folder : deletedRootFolders)
1391 removeFolderFromTrash(userId, folder.getId());
1392 List<FileHeader> deletedFiles = getDeletedFiles(userId);
1393 for (FileHeader file : deletedFiles)
1394 removeFileFromTrash(userId, file.getId());
1398 public User createUser(String username, String name, String mail,
1399 String idp, String idpid, String homeOrg) throws ObjectNotFoundException {
1400 if (username == null)
1401 throw new ObjectNotFoundException("No username specified");
1403 throw new ObjectNotFoundException("No name specified");
1405 User user = new User();
1406 user.setUsername(username);
1408 user.setEmail(mail);
1409 user.setIdentityProvider(idp);
1410 user.setIdentityProviderId(idpid);
1411 Date now = new Date();
1412 AuditInfo auditInfo = new AuditInfo();
1413 auditInfo.setCreationDate(now);
1414 auditInfo.setModificationDate(now);
1415 user.setAuditInfo(auditInfo);
1416 user.setActive(true);
1417 user.generateAuthToken();
1418 user.generateWebDAVPassword();
1419 user.setUserClass(getDefaultUserClass());
1420 user.setHomeOrganization(homeOrg);
1422 // Make sure we get an ID in the user object.
1424 // Create the root folder for the user.
1425 createFolder(user.getName(), null, user);
1430 * Get the default user class, which is the one with the lowest quota.
1432 private UserClass getDefaultUserClass() {
1433 return getUserClasses().get(0);
1437 public List<UserClass> getUserClasses() {
1438 List<UserClass> classes = dao.getUserClasses();
1439 // Create a default user class for first-time use. Afterwards, the
1440 // admin should modify or add to the userclass table.
1441 if (classes.size() == 0) {
1442 UserClass defaultClass = new UserClass();
1443 defaultClass.setName("default");
1444 Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L));
1445 defaultClass.setQuota(defaultQuota);
1446 dao.create(defaultClass);
1447 classes.add(defaultClass);
1453 public User findUserByEmail(String email) {
1454 return dao.findUserByEmail(email);
1458 public void updateUser(User user) {
1463 public User findUser(String username) {
1464 if (username == null)
1466 return dao.findUser(username);
1470 public User updateUserToken(Long userId) throws ObjectNotFoundException {
1472 throw new ObjectNotFoundException("No user specified");
1473 User user = dao.getEntityById(User.class, userId);
1474 user.generateAuthToken();
1479 public Set<Permission> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1481 throw new ObjectNotFoundException("No user specified");
1482 if (folderId == null)
1483 throw new ObjectNotFoundException("No folder specified");
1484 User user = dao.getEntityById(User.class, userId);
1485 Folder folder = dao.getEntityById(Folder.class, folderId);
1486 if(!folder.hasReadPermission(user))
1487 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1488 Set<Permission> perms = folder.getPermissions();
1489 Set<Permission> result = new LinkedHashSet<Permission>();
1490 for (Permission perm : perms)
1491 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1493 for (Permission perm : perms)
1494 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1502 * Set the provided permissions as the new permissions of the specified
1507 * @param permissions
1508 * @throws ObjectNotFoundException
1509 * @throws InsufficientPermissionsException
1511 private void setFolderPermissions(User user, Folder folder, Set<Permission> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1512 if (permissions != null && !permissions.isEmpty()) {
1513 User owner = folder.getOwner();
1514 Permission ownerPerm = null;
1515 for (Permission perm : permissions)
1516 if (perm.getUser() != null && perm.getUser().getId().equals(owner.getId())) {
1520 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1521 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1522 // Delete previous entries
1523 for (Permission perm: folder.getPermissions())
1525 folder.getPermissions().clear();
1526 for (Permission p : permissions) {
1527 // Skip 'empty' permission entries.
1528 if (!p.getRead() && !p.getWrite() && !p.getModifyACL()) continue;
1529 folder.addPermission(getPermission(p));
1532 for (FileHeader file : folder.getFiles()) {
1533 setFilePermissions(file, permissions);
1534 Date now = new Date();
1535 file.getAuditInfo().setModificationDate(now);
1536 file.getAuditInfo().setModifiedBy(user);
1538 for (Folder sub : folder.getSubfolders())
1539 setFolderPermissions(user, sub, permissions);
1543 private Permission getPermission(Permission perm) throws ObjectNotFoundException {
1544 Permission res = new Permission();
1545 if (perm.getGroup() != null)
1546 res.setGroup(dao.getEntityById(Group.class, perm.getGroup().getId()));
1547 else if (perm.getUser() != null)
1548 if (perm.getUser().getId() == null)
1549 res.setUser(dao.getUser(perm.getUser().getUsername()));
1551 res.setUser(dao.getEntityById(User.class, perm.getUser().getId()));
1552 res.setRead(perm.hasRead());
1553 res.setWrite(perm.hasWrite());
1554 res.setModifyACL(perm.hasModifyACL());
1559 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1562 public List<User> getUsersByUserNameLike(String username) {
1563 List<User> users = dao.getUsersByUserNameLike(username);
1569 public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1571 throw new ObjectNotFoundException("No user specified");
1572 if (groupId == null)
1573 throw new ObjectNotFoundException("No group specified");
1574 if (userToAddId == null)
1575 throw new ObjectNotFoundException("No user to add specified");
1576 User user = dao.getEntityById(User.class, userId);
1577 Group group = dao.getEntityById(Group.class, groupId);
1578 if (!group.getOwner().equals(user))
1579 throw new InsufficientPermissionsException();
1580 User userToAdd = dao.getEntityById(User.class, userToAddId);
1581 if (group.contains(userToAdd))
1582 throw new DuplicateNameException("User already exists in group");
1583 group.getMembers().add(userToAdd);
1589 public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1591 throw new ObjectNotFoundException("No user specified");
1592 User user = dao.getEntityById(User.class, userId);
1593 user.invalidateAuthToken();
1598 public List<Folder> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1600 throw new ObjectNotFoundException("No user specified");
1601 List<Folder> folders = dao.getSharedRootFolders(userId);
1602 List<Folder> result = new ArrayList<Folder>();
1603 for (Folder f : folders) {
1605 lf.setSubfolders(getSharedSubfolders(userId, f.getId()));
1612 public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1614 throw new ObjectNotFoundException("No user specified");
1615 if (groupId == null)
1616 throw new ObjectNotFoundException("No group specified");
1617 if (memberId == null)
1618 throw new ObjectNotFoundException("No member specified");
1619 User owner = dao.getEntityById(User.class, userId);
1620 Group group = dao.getEntityById(Group.class, groupId);
1621 User member = dao.getEntityById(User.class, memberId);
1622 if (!group.getOwner().equals(owner))
1623 throw new InsufficientPermissionsException("User is not the owner of the group");
1624 group.removeMemberFromGroup(member);
1630 public List<User> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1631 List<User> users = dao.getUsersSharingFoldersForUser(userId);
1632 List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1633 List<User> result = new ArrayList<User>();
1634 for (User u : users)
1636 for(User fu : usersFiles)
1637 if(!users.contains(fu))
1643 public Set<Permission> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1645 throw new ObjectNotFoundException("No user specified");
1647 throw new ObjectNotFoundException("No folder specified");
1648 User user = dao.getEntityById(User.class, userId);
1649 FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1650 if(!folder.hasReadPermission(user))
1651 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1652 Set<Permission> perms = folder.getPermissions();
1653 Set<Permission> result = new LinkedHashSet<Permission>();
1654 for (Permission perm : perms)
1655 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1657 for (Permission perm : perms)
1658 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1665 * Set the provided permissions as the new permissions of the specified
1666 * file. This method sets the modification date/user attributes to the
1667 * current values as a side effect.
1670 * @param permissions
1671 * @throws ObjectNotFoundException
1672 * @throws InsufficientPermissionsException
1674 private void setFilePermissions(FileHeader file,
1675 Set<Permission> permissions)
1676 throws ObjectNotFoundException, InsufficientPermissionsException {
1677 if (permissions != null && !permissions.isEmpty()) {
1678 Permission ownerPerm = null;
1679 for (Permission perm : permissions)
1680 if (perm.getUser() != null && perm.getUser().getId().equals(file.getOwner().getId())) {
1684 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1685 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1686 // Delete previous entries.
1687 for (Permission perm: file.getPermissions())
1689 file.getPermissions().clear();
1690 for (Permission perm : permissions) {
1691 // Skip 'empty' permission entries.
1692 if (!perm.getRead() && !perm.getWrite() && !perm.getModifyACL()) continue;
1693 file.addPermission(getPermission(perm));
1700 public List<FileHeader> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1702 throw new ObjectNotFoundException("No user specified");
1703 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1708 public List<FileHeader> getSharedFiles(Long userId) throws ObjectNotFoundException {
1710 throw new ObjectNotFoundException("No user specified");
1711 List<FileHeader> files = dao.getSharedFiles(userId);
1716 public List<Folder> getSharedFolders(Long userId) throws ObjectNotFoundException {
1718 throw new ObjectNotFoundException("No user specified");
1719 List<Folder> folders = dao.getSharedFolders(userId);
1724 public List<FileHeader> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1725 if (ownerId == null)
1726 throw new ObjectNotFoundException("No owner specified");
1727 if (callingUserId == null)
1728 throw new ObjectNotFoundException("No calling user specified");
1729 List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1734 public List<Folder> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1735 if (ownerId == null)
1736 throw new ObjectNotFoundException("No owner specified");
1737 if (callingUserId == null)
1738 throw new ObjectNotFoundException("No calling user specified");
1739 List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1740 List<Folder> result = new ArrayList<Folder>();
1741 for (Folder f : folders) {
1743 lf.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1751 public List<Folder> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1753 throw new ObjectNotFoundException("No user specified");
1754 if (folderId == null)
1755 throw new ObjectNotFoundException("No folder specified");
1756 User user = dao.getEntityById(User.class, userId);
1757 Folder folder = dao.getEntityById(Folder.class, folderId);
1758 List<Folder> result = new ArrayList<Folder>();
1759 if (folder.isShared(user) || folder.isReadForAll())
1760 for (Folder f : folder.getSubfolders())
1761 if ((f.isShared(user) || f.isReadForAll()) && !f.isDeleted())
1767 public List<Folder> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1769 throw new ObjectNotFoundException("No user specified");
1770 if (callingUserId == null)
1771 throw new ObjectNotFoundException("No user specified");
1772 if (folderId == null)
1773 throw new ObjectNotFoundException("No folder specified");
1774 User user = dao.getEntityById(User.class, callingUserId);
1775 Folder folder = dao.getEntityById(Folder.class, folderId);
1776 List<Folder> result = new ArrayList<Folder>();
1777 if (folder.isSharedForOtherUser(user))
1778 for (Folder f : folder.getSubfolders())
1779 if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1781 lf.setSubfolders(getSharedSubfolders(userId, callingUserId, lf.getId()));
1789 public List<FileHeader> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1790 long startTime = System.currentTimeMillis();
1792 throw new ObjectNotFoundException("No user specified");
1793 User user = getUser(userId);
1795 throw new ObjectNotFoundException("No query specified");
1796 List<FileHeader> files = search(user.getId(), query);
1798 long stopTime = System.currentTimeMillis();
1799 logger.info("Total time: " + (stopTime - startTime));
1804 * Performs the actuals search on the solr server and returns the results
1808 * @return a List of FileHeader objects
1810 private List<FileHeader> search(Long userId, String query) {
1811 final int maxRows = 100;
1812 List<FileHeader> result = new ArrayList<FileHeader>();
1814 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
1815 List<Group> groups = dao.getGroupsContainingUser(userId);
1816 String constructedQuery = escapeCharacters(normalizeSearchQuery(query)) + " AND (public: true OR ureaders: " + userId;
1817 if (!groups.isEmpty()) {
1818 constructedQuery += " OR (";
1819 for (int i=0; i<groups.size(); i++) {
1820 Group g = groups.get(i);
1821 constructedQuery += "greaders :" + g.getId();
1822 if (i < groups.size() - 1)
1823 constructedQuery += " OR ";
1825 constructedQuery += ")";
1827 constructedQuery += ")";
1828 SolrQuery solrQuery = new SolrQuery(constructedQuery);
1829 solrQuery.setRows(maxRows);
1830 long startTime = System.currentTimeMillis();
1831 QueryResponse response = solr.query(solrQuery);
1832 SolrDocumentList results = response.getResults();
1833 if (results.getNumFound() > maxRows) {
1834 solrQuery.setRows(Integer.valueOf((int) results.getNumFound()));
1835 response = solr.query(solrQuery);
1836 results = response.getResults();
1838 long stopTime = System.currentTimeMillis();
1839 logger.info("Search time:" + (stopTime - startTime));
1840 User user = getUser(userId);
1841 startTime = System.currentTimeMillis();
1842 for (SolrDocument d : results) {
1843 Long id = Long.valueOf((String) d.getFieldValue("id"));
1845 FileHeader f = dao.getEntityById(FileHeader.class, id);
1847 } catch (ObjectNotFoundException e) {
1848 logger.warn("Search result id " + id + " cannot be found", e);
1851 stopTime = System.currentTimeMillis();
1852 logger.info("File loads: " + (stopTime - startTime));
1853 } catch (MalformedURLException e) {
1855 throw new EJBException(e);
1856 } catch (SolrServerException e) {
1858 throw new EJBException(e);
1859 } catch (ObjectNotFoundException e) {
1861 throw new EJBException(e);
1867 public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1868 for(Long l : fileIds){
1869 FileHeader file = dao.getEntityById(FileHeader.class, l);
1870 copyFile(userId, l, destId, file.getName());
1877 public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1878 for(Long l : fileIds){
1879 FileHeader file = dao.getEntityById(FileHeader.class, l);
1880 moveFile(userId, l, destId, file.getName());
1886 public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1888 throw new ObjectNotFoundException("No user specified");
1889 User user = dao.getEntityById(User.class, userId);
1890 Nonce nonce = Nonce.createNonce(user.getId());
1896 public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1898 throw new ObjectNotFoundException("No user specified");
1900 throw new ObjectNotFoundException("No nonce specified");
1901 return dao.getNonce(nonce, userId);
1905 public void removeNonce(Long id) throws ObjectNotFoundException {
1907 throw new ObjectNotFoundException("No nonce specified");
1908 Nonce nonce = dao.getEntityById(Nonce.class, id);
1913 public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1915 throw new ObjectNotFoundException("No user specified");
1916 User user = dao.getEntityById(User.class, userId);
1917 user.setNonce(nonce);
1918 user.setNonceExpiryDate(nonceExpiryDate);
1922 public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1924 throw new ObjectNotFoundException("No user specified");
1925 StatsDTO stats = new StatsDTO();
1926 stats.setFileCount(dao.getFileCount(userId));
1927 Long fileSize = dao.getFileSize(userId);
1928 stats.setFileSize(fileSize);
1929 Long quota = getQuota(userId);
1930 Long quotaLeft = quota - fileSize;
1931 stats.setQuotaLeftSize(quotaLeft);
1936 public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1938 throw new ObjectNotFoundException("No user specified");
1940 throw new ObjectNotFoundException("No file specified");
1941 User user = dao.getEntityById(User.class, userId);
1942 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1943 if(!header.hasWritePermission(user))
1944 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1945 FileBody body = dao.getFileVersion(fileId, version);
1946 final File fileContents = new File(body.getStoredFilePath());
1949 updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
1950 } catch (FileNotFoundException e) {
1951 throw new GSSIOException(e);
1957 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
1960 public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1962 throw new ObjectNotFoundException("No user specified");
1964 throw new ObjectNotFoundException("No file specified");
1965 User user = dao.getEntityById(User.class, userId);
1966 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1967 if(!header.hasWritePermission(user))
1968 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1969 Iterator<FileBody> it = header.getBodies().iterator();
1970 while(it.hasNext()){
1971 FileBody body = it.next();
1972 if(!body.equals(header.getCurrentBody())){
1973 deleteActualFile(body.getStoredFilePath());
1978 header.getCurrentBody().setVersion(1);
1980 Folder parent = header.getFolder();
1981 touchParentFolders(parent, user, new Date());
1985 * Gets the quota left for specified user ID.
1987 private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
1988 Long fileSize = dao.getFileSize(userId);
1989 Long quota = getQuota(userId);
1990 return quota - fileSize;
1994 * Gets the quota for specified user ID.
1996 private Long getQuota(Long userId) throws ObjectNotFoundException{
1997 UserClass uc = getUser(userId).getUserClass();
1999 uc = getDefaultUserClass();
2000 return uc.getQuota();
2004 @TransactionAttribute(TransactionAttributeType.NEVER)
2005 public String rebuildSolrIndex() {
2007 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2008 solr.deleteByQuery("*:*");
2010 logger.info("Deleted everything in solr");
2012 List<Long> fileIds = dao.getAllFileIds();
2013 logger.info("Total of " + fileIds.size() + " will be indexed");
2015 for (Long id : fileIds) {
2017 postFileToSolr(solr, id);
2019 catch (ObjectNotFoundException e) {
2020 logger.error("Indexing of file id " + id + " failed.", e);
2025 logger.info("Sent commit to solr at file " + i);
2030 logger.info("Finished indexing of " + i + " files");
2031 return "Finished indexing of " + i + " files";
2032 } catch (IOException e) {
2033 throw new EJBException(e);
2034 } catch (SolrServerException e) {
2035 throw new EJBException(e);
2040 @TransactionAttribute(TransactionAttributeType.NEVER)
2041 public String refreshSolrIndex() {
2043 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2045 List<Long> fileIds = dao.getAllFileIds();
2046 logger.info("Total of " + fileIds.size() + " will be checked");
2048 for (Long id : fileIds) {
2049 if (!fileIsInSolr(solr, id)) {
2051 postFileToSolr(solr, id);
2053 catch (ObjectNotFoundException e) {
2054 logger.error("Indexing of file id " + id + " failed.", e);
2060 logger.info("Sent commit to solr at file " + i);
2065 logger.info("Finished indexing of " + i + " files");
2066 return "Finished indexing of " + i + " files";
2067 } catch (IOException e) {
2068 throw new EJBException(e);
2069 } catch (SolrServerException e) {
2070 throw new EJBException(e);
2074 private boolean fileIsInSolr(CommonsHttpSolrServer solr, Long id) {
2076 SolrQuery query = new SolrQuery("id:" + id);
2077 QueryResponse response = solr.query(query);
2078 return !(response.getResults().size() == 0);
2080 catch (SolrServerException e) {
2081 logger.warn("Exception while checking file " + id, e);
2087 public FileHeader createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2088 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2089 InsufficientPermissionsException, QuotaExceededException {
2092 throw new ObjectNotFoundException("No user specified");
2093 if (folderId == null)
2094 throw new ObjectNotFoundException("No folder specified");
2095 String contentType = mimeType;
2096 if (StringUtils.isEmpty(mimeType))
2097 contentType = DEFAULT_MIME_TYPE;
2098 if (StringUtils.isEmpty(name))
2099 throw new ObjectNotFoundException("No file name specified");
2100 if (dao.existsFolderOrFile(folderId, name))
2101 throw new DuplicateNameException("A folder or file with the name '" + name +
2102 "' already exists at this level");
2104 // Do the actual work.
2105 Folder parent = null;
2107 parent = dao.getEntityById(Folder.class, folderId);
2108 } catch (final ObjectNotFoundException onfe) {
2109 // Supply a more accurate problem description.
2110 throw new ObjectNotFoundException("Parent folder not found");
2112 final User owner = dao.getEntityById(User.class, userId);
2113 if (!parent.hasWritePermission(owner))
2114 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2115 final FileHeader file = new FileHeader();
2117 parent.addFile(file);
2118 // set file owner to folder owner
2119 file.setOwner(parent.getOwner());
2120 //set file's readForAll value according to parent folder readForAll value
2121 file.setReadForAll(parent.isReadForAll());
2123 final Date now = new Date();
2124 final AuditInfo auditInfo = new AuditInfo();
2125 auditInfo.setCreatedBy(owner);
2126 auditInfo.setCreationDate(now);
2127 auditInfo.setModifiedBy(owner);
2128 auditInfo.setModificationDate(now);
2129 file.setAuditInfo(auditInfo);
2130 // TODO set the proper versioning flag on creation
2131 file.setVersioned(false);
2133 for (final Permission p : parent.getPermissions()) {
2134 final Permission permission = new Permission();
2135 permission.setGroup(p.getGroup());
2136 permission.setUser(p.getUser());
2137 permission.setRead(p.getRead());
2138 permission.setWrite(p.getWrite());
2139 permission.setModifyACL(p.getModifyACL());
2140 file.addPermission(permission);
2143 // Create the file body.
2145 createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2146 } catch (FileNotFoundException e) {
2147 throw new GSSIOException(e);
2149 touchParentFolders(parent, owner, new Date());
2151 indexFile(file.getId(), false);
2157 public FileHeader updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2159 throw new ObjectNotFoundException("No user specified");
2161 throw new ObjectNotFoundException("No file specified");
2162 String contentType = mimeType;
2164 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2166 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2167 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2168 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2169 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2170 contentType = identifyMimeType(file.getName());
2172 final User owner = dao.getEntityById(User.class, userId);
2173 if (!file.hasWritePermission(owner))
2174 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2175 final Date now = new Date();
2176 final AuditInfo auditInfo = new AuditInfo();
2177 auditInfo.setCreatedBy(owner);
2178 auditInfo.setCreationDate(now);
2179 auditInfo.setModifiedBy(owner);
2180 auditInfo.setModificationDate(now);
2182 createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2183 } catch (FileNotFoundException e) {
2184 throw new GSSIOException(e);
2186 Folder parent = file.getFolder();
2187 touchParentFolders(parent, owner, new Date());
2189 indexFile(fileId, false);
2194 * Helper method for identifying mime type by examining the filename extension
2197 * @return the mime type
2199 private String identifyMimeType(String filename) {
2200 if (filename.indexOf('.') != -1) {
2201 String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2202 if (".doc".equals(extension))
2203 return "application/msword";
2204 else if (".xls".equals(extension))
2205 return "application/vnd.ms-excel";
2206 else if (".ppt".equals(extension))
2207 return "application/vnd.ms-powerpoint";
2208 else if (".pdf".equals(extension))
2209 return "application/pdf";
2210 else if (".gif".equals(extension))
2212 else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2213 return "image/jpeg";
2214 else if (".tiff".equals(extension) || ".tif".equals(extension))
2215 return "image/tiff";
2216 else if (".png".equals(extension))
2218 else if (".bmp".equals(extension))
2221 // when all else fails assign the default mime type
2222 return DEFAULT_MIME_TYPE;
2226 * Helper method to create a new file body and attach it as the current body
2227 * of the provided file header.
2229 * @param name the original file name
2230 * @param mimeType the content type
2231 * @param fileSize the uploaded file size
2232 * @param filePath the uploaded file full path
2233 * @param header the file header that will be associated with the new body
2234 * @param auditInfo the audit info
2235 * @throws FileNotFoundException
2236 * @throws QuotaExceededException
2237 * @throws ObjectNotFoundException if the owner was not found
2239 private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2240 FileHeader header, AuditInfo auditInfo)
2241 throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2243 long currentTotalSize = 0;
2244 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2245 currentTotalSize = header.getTotalSize();
2246 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2247 if(quotaLeft < fileSize-currentTotalSize) {
2248 // quota exceeded -> delete the file
2249 deleteActualFile(filePath);
2250 throw new QuotaExceededException("Not enough free space available");
2253 FileBody body = new FileBody();
2255 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2256 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2257 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2258 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2259 body.setMimeType(identifyMimeType(name));
2261 body.setMimeType(mimeType);
2262 body.setAuditInfo(auditInfo);
2263 body.setFileSize(fileSize);
2264 body.setOriginalFilename(name);
2265 body.setStoredFilePath(filePath);
2266 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2267 if(!header.isVersioned() && header.getCurrentBody() != null){
2268 header.setCurrentBody(null);
2269 if (header.getBodies() != null) {
2270 Iterator<FileBody> it = header.getBodies().iterator();
2271 while(it.hasNext()){
2272 FileBody bo = it.next();
2273 deleteActualFile(bo.getStoredFilePath());
2281 header.addBody(body);
2282 header.setAuditInfo(auditInfo);
2289 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2290 public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2292 throw new ObjectNotFoundException("No user specified");
2293 User owner = dao.getEntityById(User.class, userId);
2295 throw new ObjectNotFoundException("No user specified");
2296 long start = 0, end = 0;
2297 if (logger.isDebugEnabled())
2298 start = System.currentTimeMillis();
2299 File result = new File(generateRepositoryFilePath());
2301 final FileOutputStream output = new FileOutputStream(result);
2302 final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2305 while (-1 != (n = stream.read(buffer)))
2306 output.write(buffer, 0, n);
2309 } catch (IOException e) {
2310 if (!result.delete())
2311 logger.warn("Could not delete " + result.getPath());
2314 if (logger.isDebugEnabled()) {
2315 end = System.currentTimeMillis();
2316 logger.debug("Time to upload: " + (end - start) + " (msec)");
2323 public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2326 throw new ObjectNotFoundException("No user specified");
2327 User user = dao.getEntityById(User.class, userId);
2328 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2330 status = new FileUploadStatus();
2331 status.setOwner(user);
2332 status.setFilename(filename);
2333 status.setBytesUploaded(bytesTransfered);
2334 status.setFileSize(fileSize);
2338 status.setBytesUploaded(bytesTransfered);
2339 status.setFileSize(fileSize);
2346 public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2348 throw new ObjectNotFoundException("No user specified");
2349 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2355 public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2356 return dao.getFileUploadStatus(userId, fileName);
2360 public FileBody getFileVersion(Long userId, Long fileId, int version)
2361 throws ObjectNotFoundException, InsufficientPermissionsException {
2363 throw new ObjectNotFoundException("No user specified");
2365 throw new ObjectNotFoundException("No file specified");
2367 throw new ObjectNotFoundException("No valid version specified");
2368 User user = dao.getEntityById(User.class, userId);
2369 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2370 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2371 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2372 FileBody body = dao.getFileVersion(fileId, version);
2377 public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2379 throw new ObjectNotFoundException("No user specified");
2380 User user = dao.getEntityById(User.class, userId);
2381 user.setAcceptedPolicy(isAccepted);
2386 public void updateAccounting(User user, Date date, long bandwidthDiff) {
2387 dao.updateAccounting(user, date, bandwidthDiff);
2391 public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2393 throw new ObjectNotFoundException("No user specified");
2394 if (folderId == null)
2395 throw new ObjectNotFoundException("No folder specified");
2396 User user = dao.getEntityById(User.class, userId);
2397 Folder folder = dao.getEntityById(Folder.class, folderId);
2398 // Check permissions
2399 if (!folder.hasReadPermission(user))
2405 public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2407 throw new ObjectNotFoundException("No user specified");
2408 User user = dao.getEntityById(User.class, userId);
2409 user.generateWebDAVPassword();
2410 return user.getWebDAVPassword();
2414 public Invitation findInvite(String code) {
2417 return dao.findInvite(code);
2421 public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2422 LDAPConnection lc = new LDAPConnection();
2423 LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2424 attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2425 attributeSet.add(new LDAPAttribute("uid", username));
2426 attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2427 attributeSet.add(new LDAPAttribute("sn", lastname));
2428 attributeSet.add(new LDAPAttribute("givenName", firstname));
2429 attributeSet.add(new LDAPAttribute("mail", email));
2430 attributeSet.add(new LDAPAttribute("userPassword", password));
2431 String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2432 LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2434 lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2435 lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2436 getConfiguration().getString("bindPassword").getBytes("UTF8"));
2438 logger.info("Successfully added LDAP account: " + dn);
2440 } catch(LDAPException e) {
2441 throw new RuntimeException(e);
2442 } catch(UnsupportedEncodingException e) {
2443 throw new RuntimeException(e);
2449 public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2450 User user = findUser(username);
2452 throw new ObjectNotFoundException("The user was not found");
2453 Invitation invite = findInvite(code);
2454 if (invite.getUser() != null)
2455 throw new InvitationUsedException("This code has already been used");
2456 invite.setUser(user);
2457 UserClass couponClass = getCouponUserClass();
2458 user.setUserClass(couponClass);
2463 public UserClass getCouponUserClass() {
2464 return dao.findCouponUserClass();
2468 * Set the provided readForAll as the new readforAll value of the specified
2469 * folder and sub-folders.
2474 * @throws ObjectNotFoundException
2477 private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){
2478 if (readForAll != null && user.equals(folder.getOwner())){
2479 folder.setReadForAll(readForAll);
2481 for (FileHeader file : folder.getFiles())
2482 file.setReadForAll(readForAll);
2484 //only update subfolders when readforall is true. otherwise all sub-folders stay untouched
2485 for (Folder sub : folder.getSubfolders())
2486 setFolderReadForAll(user, sub, readForAll);
2493 * Update the userLogin with the values from the supplied object.
2496 public void addUserLogin(UserLogin userLogin) {
2497 dao.update(userLogin);
2502 * Retrieves the current session user login and the user's last login
2505 * @return a list of last two user logins
2506 * @throws ObjectNotFoundException
2509 public List<UserLogin> getLastUserLogins(Long userId) throws ObjectNotFoundException{
2510 List<UserLogin> userLoginResults = new ArrayList<UserLogin>();
2511 userLoginResults = dao.getLoginsForUser(userId);
2512 if(userLoginResults.size() == 0)
2513 throw new ObjectNotFoundException("No userlogin found for the user");
2514 //if the user logins for the first time lastLoginDate = currentLoginDate
2515 if(userLoginResults.size()==1)
2516 userLoginResults.add(userLoginResults.get(0));
2517 return userLoginResults;
2521 public void postFileToSolr(Long id) throws IOException, SolrServerException, ObjectNotFoundException {
2522 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2523 postFileToSolr(solr, id);
2527 private void postFileToSolr(CommonsHttpSolrServer solr, Long id) throws ObjectNotFoundException {
2529 FileHeader file = dao.getFileForIndexing(id);
2530 FileBody body = file.getCurrentBody();
2531 String mime = body.getMimeType();
2532 boolean multipart = true;
2533 if (!mime.equals("application/pdf")
2534 && !mime.equals("text/plain")
2535 && !mime.equals("text/html")
2536 && !mime.endsWith("msword")
2537 && !mime.endsWith("ms-excel")
2538 && !mime.endsWith("powerpoint")
2539 || (body.getFileSize() > getConfiguration().getLong("solrDocumentUploadLimitInKB") * 1024))
2543 sendMetaDataOnly(solr, file);
2545 ContentStreamUpdateRequest solrRequest = new ContentStreamUpdateRequest(getConfiguration().getString("solr.rich.update.path"));
2546 solrRequest.setParam("literal.id", file.getId().toString());
2547 solrRequest.setParam("literal.name", file.getName());
2548 for (FileTag t : file.getFileTags()) {
2549 solrRequest.getParams().add("literal.tag", t.getTag());
2551 for (Permission p : file.getPermissions()) {
2553 if (p.getUser() != null)
2554 solrRequest.getParams().add("literal.ureaders", p.getUser().getId().toString());
2555 else if (p.getGroup() != null)
2556 solrRequest.getParams().add("literal.greaders", p.getGroup().getId().toString());
2559 solrRequest.setParam("literal.owner", file.getOwner().getId().toString());
2560 solrRequest.setParam("literal.public", String.valueOf(file.isReadForAll()));
2561 File fsFile = new File(body.getStoredFilePath());
2562 solrRequest.addFile(fsFile);
2564 solr.request(solrRequest);
2566 catch (SolrException e) {
2567 logger.warn("File " + id + " failed with SolrException: " + e.getLocalizedMessage() + ". Retrying without the file");
2568 //Let 's try without the file
2569 sendMetaDataOnly(solr, file);
2571 catch (NullPointerException e) {
2572 logger.warn("File " + id + " failed with NullPointerException: " + e.getLocalizedMessage() + ". Retrying without the file");
2573 //Let 's try without the file
2574 sendMetaDataOnly(solr, file);
2576 catch (SolrServerException e) {
2577 logger.warn("File " + id + " failed with SolrServerException: " + e.getLocalizedMessage() + ". Retrying without the file");
2578 //Let 's try without the file
2579 sendMetaDataOnly(solr, file);
2582 } catch (MalformedURLException e) {
2583 throw new EJBException(e);
2584 } catch (SolrServerException e) {
2585 throw new EJBException(e);
2586 } catch (IOException e) {
2587 throw new EJBException(e);
2591 private void sendMetaDataOnly(CommonsHttpSolrServer solr, FileHeader file) throws SolrServerException, IOException {
2592 SolrInputDocument solrDoc = new SolrInputDocument();
2593 solrDoc.addField("id", file.getId().toString());
2594 solrDoc.addField("name", file.getName());
2595 for (FileTag t : file.getFileTags()) {
2596 solrDoc.addField("tag", t.getTag());
2598 for (Permission p : file.getPermissions()) {
2600 if (p.getUser() != null)
2601 solrDoc.addField("ureaders", p.getUser().getId());
2602 else if (p.getGroup() != null)
2603 solrDoc.addField("greaders", p.getGroup().getId());
2606 solrDoc.addField("owner", file.getOwner().getId());
2607 solrDoc.addField("public", file.isReadForAll());
2611 private String tokenizeFilename(String filename){
2612 StringBuffer result = new StringBuffer();
2613 StringTokenizer tokenizer = new StringTokenizer(filename,"._");
2614 while(tokenizer.hasMoreTokens()){
2615 result.append(tokenizer.nextToken());
2618 result.append(filename);
2619 return result.toString();
2622 private String normalizeSearchQuery(String query) {
2623 if (query.contains("*"))
2624 return query.toLowerCase().replace('ά', 'α').replace('έ', 'ε').replace('ί', 'ι').replace('ή', 'η').replace('ύ', 'υ')
2625 .replace('ό', 'ο').replace('ς', 'σ').replace('ώ', 'ω').replace('ϊ', 'ι').replace('ϋ', 'υ');
2630 private String escapeCharacters(String text) {
2631 return text.replaceAll(":", "\\\\:");
2634 /*** NEW METHODS IN ORDER TO AVOID LAZY loading exception in json render
2637 public Folder expandFolder(Folder folder) throws ObjectNotFoundException{
2638 Folder result = dao.getEntityById(Folder.class, folder.getId());
2639 result.getSubfolders().size();
2640 result.getFiles().size();
2641 result.getPermissions().size();
2646 public FileHeader expandFile(FileHeader folder) throws ObjectNotFoundException{
2647 FileHeader result = dao.getEntityById(FileHeader.class, folder.getId());
2649 result.getPermissions().size();
2650 result.getFileTags().size();
2655 public Group expandGroup(Group folder) throws ObjectNotFoundException{
2656 Group result = dao.getEntityById(Group.class, folder.getId());
2657 result.getMembers().size();
2662 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
2665 public User getUserByUserName(String username) {
2666 User result = dao.getUserByUserName(username);
2670 /*WEBDAV CREATE EMPTY FILE*/
2672 public FileHeader createEmptyFile(Long userId, Long folderId, String name)
2673 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2674 InsufficientPermissionsException, QuotaExceededException {
2677 throw new ObjectNotFoundException("No user specified");
2678 if (folderId == null)
2679 throw new ObjectNotFoundException("No folder specified");
2680 String contentType = DEFAULT_MIME_TYPE;
2681 if (StringUtils.isEmpty(name))
2682 throw new ObjectNotFoundException("No file name specified");
2683 if (dao.existsFolderOrFile(folderId, name))
2684 throw new DuplicateNameException("A folder or file with the name '" + name +
2685 "' already exists at this level");
2687 // Do the actual work.
2688 Folder parent = null;
2690 parent = dao.getEntityById(Folder.class, folderId);
2691 } catch (final ObjectNotFoundException onfe) {
2692 // Supply a more accurate problem description.
2693 throw new ObjectNotFoundException("Parent folder not found");
2695 final User owner = dao.getEntityById(User.class, userId);
2696 if (!parent.hasWritePermission(owner))
2697 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2698 final FileHeader file = new FileHeader();
2700 parent.addFile(file);
2701 // set file owner to folder owner
2702 file.setOwner(parent.getOwner());
2703 //set file's readForAll value according to parent folder readForAll value
2704 file.setReadForAll(parent.isReadForAll());
2706 final Date now = new Date();
2707 final AuditInfo auditInfo = new AuditInfo();
2708 auditInfo.setCreatedBy(owner);
2709 auditInfo.setCreationDate(now);
2710 auditInfo.setModifiedBy(owner);
2711 auditInfo.setModificationDate(now);
2712 file.setAuditInfo(auditInfo);
2713 // TODO set the proper versioning flag on creation
2714 file.setVersioned(false);
2716 for (final Permission p : parent.getPermissions()) {
2717 final Permission permission = new Permission();
2718 permission.setGroup(p.getGroup());
2719 permission.setUser(p.getUser());
2720 permission.setRead(p.getRead());
2721 permission.setWrite(p.getWrite());
2722 permission.setModifyACL(p.getModifyACL());
2723 file.addPermission(permission);
2725 // Create the file body.
2727 createEmptyFileBody(name, contentType, 0, file, auditInfo);
2728 } catch (FileNotFoundException e) {
2729 throw new GSSIOException(e);
2731 touchParentFolders(parent, owner, new Date());
2736 private void createEmptyFileBody(String name, String mimeType, long fileSize,
2737 FileHeader header, AuditInfo auditInfo)
2738 throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2740 long currentTotalSize = 0;
2741 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2742 currentTotalSize = header.getTotalSize();
2743 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2746 FileBody body = new FileBody();
2748 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2749 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2750 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2751 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2752 body.setMimeType(identifyMimeType(name));
2754 body.setMimeType(mimeType);
2755 body.setAuditInfo(auditInfo);
2756 body.setFileSize(fileSize);
2757 body.setOriginalFilename(name);
2758 body.setStoredFilePath(generateRepositoryFilePath());
2759 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2760 if(!header.isVersioned() && header.getCurrentBody() != null){
2761 header.setCurrentBody(null);
2762 if (header.getBodies() != null) {
2763 Iterator<FileBody> it = header.getBodies().iterator();
2764 while(it.hasNext()){
2765 FileBody bo = it.next();
2766 deleteActualFile(bo.getStoredFilePath());
2774 header.addBody(body);
2775 header.setAuditInfo(auditInfo);
2779 /*** WEBDAV LOCK **/
2781 public FileLock getLockById(String id) {
2782 return dao.getLockById(id);
2786 public FileLock getLockByToken(String tokenId) {
2787 return dao.getLockByToken(tokenId);
2791 public void removeLock(FileLock lock) {
2792 dao.removeLock(lock);
2796 public FileLock saveOrUpdateLock(FileLock lock) {
2797 return dao.saveOrUpdateLock(lock);
2801 public WebDavNonce getWebDavNonce(String tokenId) {
2802 return dao.getWebDavNonce(tokenId);
2806 public void removeWebDavNonce(WebDavNonce nonce) {
2807 dao.removeWebDavNonce(nonce);
2811 public WebDavNonce saveOrUpdateWebDavNonce(WebDavNonce nonce) {
2812 return dao.saveOrUpdateWebDavNonce(nonce);