2 * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd.
4 * This file is part of GSS.
6 * GSS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GSS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GSS. If not, see <http://www.gnu.org/licenses/>.
19 package gr.ebs.gss.server.ejb;
21 import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
23 import gr.ebs.gss.admin.client.ui.UsersTable;
24 import gr.ebs.gss.client.exceptions.DuplicateNameException;
25 import gr.ebs.gss.client.exceptions.GSSIOException;
26 import gr.ebs.gss.client.exceptions.InsufficientPermissionsException;
27 import gr.ebs.gss.client.exceptions.InvitationUsedException;
28 import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
29 import gr.ebs.gss.client.exceptions.QuotaExceededException;
30 import gr.ebs.gss.server.domain.AuditInfo;
31 import gr.ebs.gss.server.domain.FileBody;
32 import gr.ebs.gss.server.domain.FileHeader;
33 import gr.ebs.gss.server.domain.FileTag;
34 import gr.ebs.gss.server.domain.FileUploadStatus;
35 import gr.ebs.gss.server.domain.Folder;
36 import gr.ebs.gss.server.domain.Group;
37 import gr.ebs.gss.server.domain.Invitation;
38 import gr.ebs.gss.server.domain.Nonce;
39 import gr.ebs.gss.server.domain.Permission;
40 import gr.ebs.gss.server.domain.User;
41 import gr.ebs.gss.server.domain.UserClass;
42 import gr.ebs.gss.server.domain.UserLogin;
43 import gr.ebs.gss.server.domain.dto.StatsDTO;
44 import gr.ebs.gss.server.domain.dto.UserDTO;
47 import java.io.FileInputStream;
48 import java.io.FileNotFoundException;
49 import java.io.FileOutputStream;
50 import java.io.IOException;
51 import java.io.InputStream;
52 import java.io.UnsupportedEncodingException;
53 import java.net.MalformedURLException;
54 import java.util.ArrayList;
55 import java.util.Date;
56 import java.util.Iterator;
57 import java.util.LinkedHashSet;
58 import java.util.List;
59 import java.util.Locale;
60 import java.util.Random;
62 import java.util.StringTokenizer;
65 import javax.ejb.EJBException;
66 import javax.ejb.EJBTransactionRolledbackException;
67 import javax.ejb.Stateless;
68 import javax.ejb.TransactionAttribute;
69 import javax.ejb.TransactionAttributeType;
70 import javax.jms.Connection;
71 import javax.jms.ConnectionFactory;
72 import javax.jms.JMSException;
73 import javax.jms.MapMessage;
74 import javax.jms.MessageProducer;
75 import javax.jms.Queue;
76 import javax.jms.QueueConnectionFactory;
77 import javax.jms.Session;
78 import javax.naming.Context;
79 import javax.naming.InitialContext;
80 import javax.naming.NamingException;
81 import javax.persistence.PersistenceException;
83 import org.apache.commons.lang.StringUtils;
84 import org.apache.commons.logging.Log;
85 import org.apache.commons.logging.LogFactory;
86 import org.apache.solr.client.solrj.SolrQuery;
87 import org.apache.solr.client.solrj.SolrServerException;
88 import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
89 import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
90 import org.apache.solr.client.solrj.response.QueryResponse;
91 import org.apache.solr.common.SolrDocument;
92 import org.apache.solr.common.SolrDocumentList;
93 import org.apache.solr.common.SolrException;
94 import org.apache.solr.common.SolrInputDocument;
95 import org.hibernate.exception.ConstraintViolationException;
97 import com.novell.ldap.LDAPAttribute;
98 import com.novell.ldap.LDAPAttributeSet;
99 import com.novell.ldap.LDAPConnection;
100 import com.novell.ldap.LDAPEntry;
101 import com.novell.ldap.LDAPException;
104 * The concrete implementation of the ExternalAPI interface.
109 public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
111 * The default MIME type for files without an explicit one.
113 private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
116 * The size of the buffer that is used to temporarily store chunks of
117 * uploaded files, while storing them to the file repository.
119 private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
124 private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
127 * Injected reference to the GSSDAO data access facade.
134 * A cached random number generator for creating unique filenames.
136 private static Random random = new Random();
139 * Mark the folder and all of its parent folders as modified from the specified user.
141 private void touchParentFolders(Folder folder, User user, Date date) {
144 AuditInfo ai = f.getAuditInfo();
145 ai.setModifiedBy(user);
146 ai.setModificationDate(date);
152 private Long getRootFolderId(Long userId) throws ObjectNotFoundException {
154 throw new ObjectNotFoundException("No user specified");
155 return dao.getRootFolderId(userId);
159 public Folder getRootFolder(Long userId) throws ObjectNotFoundException {
161 throw new ObjectNotFoundException("No user specified");
162 Folder folder = dao.getRootFolder(userId);
167 public Folder getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
169 throw new ObjectNotFoundException("No user specified");
170 if (folderId == null)
171 throw new ObjectNotFoundException("No folder specified");
172 final User user = dao.getEntityById(User.class, userId);
173 final Folder folder = dao.getEntityById(Folder.class, folderId);
175 if (!folder.hasReadPermission(user))
176 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
181 public User getUser(Long userId) throws ObjectNotFoundException {
183 throw new ObjectNotFoundException("No user specified");
184 return dao.getEntityById(User.class, userId);
188 public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
189 return getUser(userId).getDTO();
193 public Group getGroup(final Long groupId) throws ObjectNotFoundException {
195 throw new ObjectNotFoundException("No group specified");
196 final Group group = dao.getEntityById(Group.class, groupId);
201 public Group getGroup(Long userId, String name) throws ObjectNotFoundException {
203 throw new ObjectNotFoundException("No user specified");
205 throw new ObjectNotFoundException("No group specified");
206 User user = dao.getEntityById(User.class, userId);
207 List<Group> groups = user.getGroupsSpecified();
208 for (Group group: groups)
209 if (group.getName().equals(name))
211 throw new ObjectNotFoundException("Group " + name + " not found");
215 public List<Group> getGroups(final Long userId) throws ObjectNotFoundException {
217 throw new ObjectNotFoundException("No user specified");
218 final List<Group> groups = dao.getGroups(userId);
223 public List<FileHeader> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
224 throws ObjectNotFoundException, InsufficientPermissionsException {
227 throw new ObjectNotFoundException("No user specified");
228 if (folderId == null)
229 throw new ObjectNotFoundException("No folder specified");
230 User user = dao.getEntityById(User.class, userId);
231 Folder folder = dao.getEntityById(Folder.class, folderId);
232 if (!folder.hasReadPermission(user))
233 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
234 List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
239 public List<User> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
242 throw new ObjectNotFoundException("No user specified");
244 throw new ObjectNotFoundException("No group specified");
246 // Do the actual work.
247 final List<User> users = dao.getUsers(groupId);
252 public Folder createFolder(Long userId, Long parentId, String name)
253 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
256 throw new ObjectNotFoundException("No user specified");
257 if (StringUtils.isEmpty(name))
258 throw new ObjectNotFoundException("New folder name is empty");
259 if (parentId == null)
260 throw new ObjectNotFoundException("No parent specified");
261 if (dao.existsFolderOrFile(parentId, name))
262 throw new DuplicateNameException("A folder or file with the name '" +
263 name + "' already exists at this level");
265 User creator = dao.getEntityById(User.class, userId);
267 Folder parent = null;
269 parent = dao.getEntityById(Folder.class, parentId);
270 } catch (ObjectNotFoundException onfe) {
271 // Supply a more accurate problem description.
272 throw new ObjectNotFoundException("Parent folder not found");
274 if (!parent.hasWritePermission(creator))
275 throw new InsufficientPermissionsException("You don't have the permissions" +
276 " to write to this folder");
278 // Do the actual work.
279 return createFolder(name, parent, creator);
283 * Create a new folder with the provided name, parent and owner.
288 * @return the new folder
290 private Folder createFolder(String name, Folder parent, User creator) {
291 Folder folder = new Folder();
292 folder.setName(name);
293 if (parent != null) {
294 parent.addSubfolder(folder);
295 folder.setOwner(parent.getOwner());
297 folder.setOwner(creator);
299 Date now = new Date();
300 AuditInfo auditInfo = new AuditInfo();
301 auditInfo.setCreatedBy(creator);
302 auditInfo.setCreationDate(now);
303 auditInfo.setModifiedBy(creator);
304 auditInfo.setModificationDate(now);
305 folder.setAuditInfo(auditInfo);
306 touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
309 for (Permission p : parent.getPermissions()) {
310 Permission permission = new Permission();
311 permission.setGroup(p.getGroup());
312 permission.setUser(p.getUser());
313 permission.setRead(p.getRead());
314 permission.setWrite(p.getWrite());
315 permission.setModifyACL(p.getModifyACL());
316 folder.addPermission(permission);
319 Permission permission = new Permission();
320 permission.setUser(creator);
321 permission.setRead(true);
322 permission.setWrite(true);
323 permission.setModifyACL(true);
324 folder.addPermission(permission);
328 folder.setReadForAll(parent.isReadForAll());
335 public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
338 throw new ObjectNotFoundException("No user specified");
339 if (folderId == null)
340 throw new ObjectNotFoundException("No folder specified");
342 // Do the actual work.
343 final Folder folder = dao.getEntityById(Folder.class, folderId);
344 final Folder parent = folder.getParent();
346 throw new ObjectNotFoundException("Deleting the root folder is not allowed");
347 final User user = dao.getEntityById(User.class, userId);
348 if (!folder.hasDeletePermission(user)) {
349 logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
350 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
352 removeSubfolderFiles(folder);
353 parent.removeSubfolder(folder);
355 touchParentFolders(parent, user, new Date());
359 * Traverses the folder and deletes all actual files (file system)
360 * regardless of permissions
364 private void removeSubfolderFiles(Folder folder) {
365 //remove files for all subfolders
366 for (Folder subfolder:folder.getSubfolders())
367 removeSubfolderFiles(subfolder);
368 //remove this folder's file bodies (actual files)
369 for (FileHeader file:folder.getFiles()) {
370 for (FileBody body:file.getBodies())
371 deleteActualFile(body.getStoredFilePath());
372 indexFile(file.getId(), true);
377 @SuppressWarnings("unchecked")
378 public List<Folder> getSubfolders(Long userId, Long folderId)
379 throws ObjectNotFoundException, InsufficientPermissionsException {
381 throw new ObjectNotFoundException("No user specified");
382 if (folderId == null)
383 throw new ObjectNotFoundException("No folder specified");
384 User user = dao.getEntityById(User.class, userId);
385 Folder folder = dao.getEntityById(Folder.class, folderId);
386 if (!folder.hasReadPermission(user))
387 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
388 List<Folder> result = new ArrayList<Folder>();
389 if (folder.hasReadPermission(user))
390 for (Folder f : folder.getSubfolders())
391 if (f.hasReadPermission(user) && !f.isDeleted())
397 public Folder updateFolder(Long userId, Long folderId, String folderName,
399 Set<Permission> permissions)
400 throws InsufficientPermissionsException, ObjectNotFoundException,
401 DuplicateNameException {
405 throw new ObjectNotFoundException("No user specified");
406 if (folderId == null)
407 throw new ObjectNotFoundException("No folder specified");
409 Folder folder = dao.getEntityById(Folder.class, folderId);
410 User user = dao.getEntityById(User.class, userId);
411 if (folderName != null && !folder.hasWritePermission(user))
412 throw new InsufficientPermissionsException("You don't have the necessary permissions");
413 if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
414 throw new InsufficientPermissionsException("You don't have the necessary permissions");
415 // Check permissions for making file public.
416 if (readForAll != null && !user.equals(folder.getOwner()))
417 throw new InsufficientPermissionsException("Only the owner can make a folder public or not public");
419 Folder parent = folder.getParent();
420 if (folderName != null) {
422 if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
423 throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
425 // Do the actual modification.
426 folder.setName(folderName);
428 if (permissions != null)
429 setFolderPermissions(user, folder, permissions);
430 if (readForAll != null)
431 setFolderReadForAll(user, folder, readForAll);
432 folder.getAuditInfo().setModificationDate(new Date());
433 folder.getAuditInfo().setModifiedBy(user);
435 touchParentFolders(folder, user, new Date());
436 // Re-index the folder contents if it was modified.
437 if ((permissions != null && !permissions.isEmpty()) || readForAll != null) {
444 private void indexFolder(Folder folder) {
445 for (FileHeader fh : folder.getFiles())
446 indexFile(fh.getId(), false);
447 for (Folder f : folder.getSubfolders())
452 public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
455 throw new ObjectNotFoundException("No user specified");
456 if (StringUtils.isEmpty(name))
457 throw new ObjectNotFoundException("New group name is empty");
458 if (name.indexOf('/')>=0)
459 throw new IllegalArgumentException("Character '/' is not allowed in group name");
460 if (dao.existsGroup(userId, name))
461 throw new DuplicateNameException("A group with the name '" + name + "' already exists");
463 // TODO: Check permissions
465 final User owner = dao.getEntityById(User.class, userId);
467 // Do the actual work.
468 owner.createGroup(name);
472 public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
475 throw new ObjectNotFoundException("No user specified");
477 throw new ObjectNotFoundException("No group specified");
479 // Do the actual work.
480 final User owner = dao.getEntityById(User.class, userId);
481 final Group group = dao.getEntityById(Group.class, groupId);
482 final Date now = new Date();
483 // Only delete the group if actually owned by the user.
484 if (group.getOwner().equals(owner)) {
485 List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
486 for (Folder f : folders){
487 f.getPermissions().removeAll(group.getPermissions());
488 for(FileHeader file : f.getFiles()){
489 file.getPermissions().removeAll(group.getPermissions());
492 List<FileHeader> files = dao.getFilesPermittedForGroup(userId, groupId);
493 for(FileHeader h : files){
494 h.getPermissions().removeAll(group.getPermissions());
496 owner.removeSpecifiedGroup(group);
499 else throw new InsufficientPermissionsException("You are not the owner of this group");
503 public FileHeader createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
504 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
505 InsufficientPermissionsException, QuotaExceededException {
508 file = uploadFile(stream, userId);
509 } catch ( IOException ioe) {
510 // Supply a more accurate problem description.
511 throw new GSSIOException("Problem creating file",ioe);
513 return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
517 * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
520 public void indexFile(Long fileId, boolean delete) {
521 Connection qConn = null;
522 Session session = null;
523 MessageProducer sender = null;
525 Context jndiCtx = new InitialContext();
526 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
527 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
528 qConn = factory.createConnection();
529 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
530 sender = session.createProducer(queue);
532 MapMessage map = session.createMapMessage();
533 map.setObject("id", fileId);
534 map.setBoolean("delete", delete);
537 catch (NamingException e) {
538 logger.error("Index was not updated: ", e);
540 catch (JMSException e) {
541 logger.error("Index was not updated: ", e);
552 catch (JMSException e) {
561 * A helper method that generates a unique file path for a stored file. The
562 * files are stored using random hash names that are distributed evenly in
563 * a 2-level tree of subdirectories named after the first two hex characters
564 * in the name. For example, file ab1234cd5769f will be stored in the path
565 * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
566 * if they don't already exist.
568 * @return a unique new file path
570 private String generateRepositoryFilePath() {
571 String filename = Long.toHexString(random.nextLong());
572 String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
573 File root = new File(fileRepositoryPath);
576 File firstFolder = new File(root + File.separator + filename.substring(0, 1));
577 if (!firstFolder.exists())
579 File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
580 if (!secondFolder.exists())
581 secondFolder.mkdir();
582 return secondFolder + File.separator + filename;
586 public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
589 throw new ObjectNotFoundException("No user specified");
591 throw new ObjectNotFoundException("No file specified");
593 // Do the actual work.
594 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
595 final Folder parent = file.getFolder();
597 throw new ObjectNotFoundException("The specified file has no parent folder");
598 final User user = dao.getEntityById(User.class, userId);
599 if (!file.hasDeletePermission(user))
600 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
601 for (final FileBody body : file.getBodies())
602 deleteActualFile(body.getStoredFilePath());
604 touchParentFolders(parent, user, new Date());
605 indexFile(fileId, true);
609 public void deleteActualFile(String path) {
612 File file = new File(path);
614 logger.error("Could not delete file " + path);
618 public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
620 throw new ObjectNotFoundException("No user specified");
621 if (fileHeaderId == null)
622 throw new ObjectNotFoundException("No file specified");
623 if (StringUtils.isEmpty(tag))
624 throw new ObjectNotFoundException("Tag is empty");
626 final User user = dao.getEntityById(User.class, userId);
627 final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
628 final Folder parent = fh.getFolder();
630 throw new ObjectNotFoundException("The specified file has no parent folder");
631 user.addTag(fh, tag);
632 touchParentFolders(parent, user, new Date());
636 public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
637 return dao.getUserTags(userId);
641 public void updateFile(Long userId, Long fileId, String name,
642 String tagSet, Date modificationDate, Boolean versioned,
643 Boolean readForAll, Set<Permission> permissions)
644 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
646 throw new ObjectNotFoundException("No user specified");
648 throw new ObjectNotFoundException("No file specified");
649 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
650 final Folder parent = file.getFolder();
652 throw new ObjectNotFoundException("The specified file has no parent folder");
654 User user = dao.getEntityById(User.class, userId);
655 // Check permissions for modifying the file metadata.
656 if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
657 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
658 // Check permissions for making file public.
659 if (readForAll != null && !user.equals(file.getOwner()))
660 throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
661 // Check permissions for modifying the ACL.
662 if(permissions != null && !permissions.isEmpty() && !file.hasModifyACLPermission(user))
663 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update the permissions on file " + file.getName() + "(" + file.getId() + ")");
666 // Do plain check for file already exists.
667 // Extreme concurrency case should be caught by constraint violation later.
668 if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
672 if (modificationDate != null)
673 file.getAuditInfo().setModificationDate(modificationDate);
675 file.getAuditInfo().setModificationDate(new Date());
676 file.getAuditInfo().setModifiedBy(user);
678 List<FileTag> tags = file.getFileTags();
679 if (tagSet != null) {
680 Iterator<FileTag> i = tags.iterator();
681 while (i.hasNext()) {
682 FileTag tag = i.next();
689 StringTokenizer st = new StringTokenizer(tagSet, ",");
690 while (st.hasMoreTokens())
691 new FileTag(user, file, st.nextToken().trim());
693 if (versioned != null && !file.isVersioned() == versioned) {
694 if (file.isVersioned())
695 removeOldVersions(userId, fileId);
696 file.setVersioned(versioned);
698 if (readForAll != null && user.equals(file.getOwner()))
699 file.setReadForAll(readForAll);
700 if (permissions != null && !permissions.isEmpty())
701 setFilePermissions(file, permissions);
704 * Force constraint violation to manifest itself here.
705 * This should cover extreme concurrency cases that the simple check
706 * above hasn't caught.
711 catch (EJBTransactionRolledbackException e) {
712 Throwable cause = e.getCause();
713 if (cause instanceof PersistenceException && cause.getCause() instanceof ConstraintViolationException)
714 throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
718 touchParentFolders(parent, user, new Date());
720 // Re-index the file if it was modified.
721 if (name != null || tagSet != null || (permissions != null && !permissions.isEmpty()) || readForAll != null)
722 indexFile(fileId, false);
726 public InputStream getFileContents(Long userId, Long fileId)
727 throws ObjectNotFoundException, InsufficientPermissionsException {
729 throw new ObjectNotFoundException("No user specified");
731 throw new ObjectNotFoundException("No file specified");
733 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
734 User user = dao.getEntityById(User.class, userId);
735 if (!header.hasReadPermission(user)) {
736 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
737 throw new InsufficientPermissionsException("You don't have the necessary permissions");
740 File f = new File(header.getCurrentBody().getStoredFilePath());
742 return new FileInputStream(f);
743 } catch (FileNotFoundException e) {
744 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
745 throw new ObjectNotFoundException("The file contents could not be located");
750 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
753 public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
755 throw new ObjectNotFoundException("No user specified");
757 throw new ObjectNotFoundException("No file specified");
759 throw new ObjectNotFoundException("No file specified");
761 final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
762 final FileBody body = dao.getEntityById(FileBody.class, bodyId);
763 final User user = dao.getEntityById(User.class, userId);
764 if (!header.hasReadPermission(user)) {
765 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
766 throw new InsufficientPermissionsException("You don't have the necessary permissions");
769 File f = new File(body.getStoredFilePath());
771 return new FileInputStream(f);
772 } catch (FileNotFoundException e) {
773 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
774 throw new ObjectNotFoundException("The file contents could not be located");
779 public FileHeader getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
781 throw new ObjectNotFoundException("No user specified");
783 throw new ObjectNotFoundException("No file specified");
784 final User user = dao.getEntityById(User.class, userId);
785 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
786 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
787 throw new InsufficientPermissionsException("You don't have the necessary permissions");
792 public FileBody getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
794 throw new ObjectNotFoundException("No user specified");
796 throw new ObjectNotFoundException("No file specified");
797 User user = dao.getEntityById(User.class, userId);
798 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
799 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
800 throw new InsufficientPermissionsException("You don't have the necessary permissions");
801 FileBody body = dao.getEntityById(FileBody.class, bodyId);
806 public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
807 throws ObjectNotFoundException {
809 throw new ObjectNotFoundException("No user specified");
810 if (StringUtils.isEmpty(path))
811 throw new ObjectNotFoundException("No path specified");
813 User owner = dao.getEntityById(User.class, ownerId);
814 List<String> pathElements = new ArrayList<String>();
815 StringTokenizer st = new StringTokenizer(path, "/");
816 while (st.hasMoreTokens())
817 pathElements.add(st.nextToken());
818 if (pathElements.size() < 1)
819 return getRootFolder(owner.getId());
820 // Store the last element, since it requires special handling.
821 String lastElement = pathElements.remove(pathElements.size() - 1);
823 Folder cursor = null;
824 Long rootFolderId = getRootFolderId(owner.getId());
825 // Traverse and verify the specified folder path.
826 for (String pathElement : pathElements) {
827 cursor = getFolder(cursor==null ? rootFolderId : cursor.getId(), pathElement);
828 if (cursor.isDeleted())
829 throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
832 // Use the lastElement to retrieve the actual resource.
833 Object resource = null;
835 FileHeader file = getFile(cursor==null ? rootFolderId : cursor.getId(), lastElement);
836 if (ignoreDeleted && file.isDeleted())
837 throw new ObjectNotFoundException("Resource not found");
839 } catch (ObjectNotFoundException e) {
840 // Perhaps the requested resource is not a file, so
841 // check for folders as well.
842 Folder folder = getFolder(cursor==null ? rootFolderId : cursor.getId(), lastElement).getDTO();
843 if (ignoreDeleted && folder.isDeleted())
844 throw new ObjectNotFoundException("Resource not found");
851 * Retrieve a file for the specified user that has the specified name and
852 * its parent folder has id equal to folderId.
854 * @param folderId the ID of the parent folder
855 * @param name the name of the requested file
856 * @return the file found
857 * @throws ObjectNotFoundException if the specified folder or file was not
858 * found, with the exception message mentioning the precise
861 private FileHeader getFile(Long folderId, String name) throws ObjectNotFoundException {
862 if (folderId == null)
863 throw new ObjectNotFoundException("No parent folder specified");
864 if (StringUtils.isEmpty(name))
865 throw new ObjectNotFoundException("No file specified");
867 FileHeader file = dao.getFile(folderId, name);
872 * Retrieve a folder for the specified user that has the specified name and
873 * its parent folder has id equal to parentId.
875 * @param parentId the ID of the parent folder
876 * @param name the name of the requested folder
877 * @return the folder found
878 * @throws ObjectNotFoundException if the specified folder or parent was not
879 * found, with the exception message mentioning the precise
882 private Folder getFolder(Long parentId, String name) throws ObjectNotFoundException {
883 if (parentId == null)
884 throw new ObjectNotFoundException("No parent folder specified");
885 if (StringUtils.isEmpty(name))
886 throw new ObjectNotFoundException("No folder specified");
888 Folder folder = dao.getFolder(parentId, name);
892 private FileHeader updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
895 file = uploadFile(resourceInputStream, userId);
896 } catch ( IOException ioe) {
897 // Supply a more accurate problem description.
898 throw new GSSIOException("Problem creating file",ioe);
900 return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
904 public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
906 throw new ObjectNotFoundException("No user specified");
908 throw new ObjectNotFoundException("No file specified");
909 if (StringUtils.isEmpty(dest))
910 throw new ObjectNotFoundException("No destination specified");
912 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
913 if (!(destination instanceof Folder))
914 throw new ObjectNotFoundException("Destination parent folder not found");
915 Folder parent = (Folder) destination;
916 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
920 public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
922 throw new ObjectNotFoundException("No user specified");
924 throw new ObjectNotFoundException("No owner specified");
926 throw new ObjectNotFoundException("No file specified");
927 if (StringUtils.isEmpty(dest))
928 throw new ObjectNotFoundException("No destination specified");
930 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
931 if (!(destination instanceof Folder))
932 throw new ObjectNotFoundException("Destination parent folder not found");
933 Folder parent = (Folder) destination;
934 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
938 public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
940 throw new ObjectNotFoundException("No user specified");
942 throw new ObjectNotFoundException("No file specified");
944 throw new ObjectNotFoundException("No destination specified");
945 if (StringUtils.isEmpty(destName))
946 throw new ObjectNotFoundException("No destination file name specified");
948 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
949 Folder destination = dao.getEntityById(Folder.class, destId);
950 User user = dao.getEntityById(User.class, userId);
951 if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
952 throw new InsufficientPermissionsException("You don't have the necessary permissions");
953 boolean versioned = file.isVersioned();
954 int versionsNumber = file.getBodies().size();
955 FileBody oldestBody = file.getBodies().get(0);
956 assert oldestBody != null;
957 File contents = new File(oldestBody.getStoredFilePath());
959 createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
960 FileHeader copiedFile = dao.getFile(destination.getId(), destName);
961 copiedFile.setVersioned(versioned);
963 if (versionsNumber > 1)
964 for (int i = 1; i < versionsNumber; i++) {
965 FileBody body = file.getBodies().get(i);
967 contents = new File(body.getStoredFilePath());
968 updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
970 List<FileTag> tags = file.getFileTags();
971 for (FileTag tag : tags)
972 createTag(userId, copiedFile.getId(), tag.getTag());
974 } catch (FileNotFoundException e) {
975 throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
981 public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
983 throw new ObjectNotFoundException("No user specified");
984 if (folderId == null)
985 throw new ObjectNotFoundException("No folder specified");
986 if (StringUtils.isEmpty(dest))
987 throw new ObjectNotFoundException("No destination specified");
989 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
990 if (!(destination instanceof Folder))
991 throw new ObjectNotFoundException("Destination folder not found");
992 Folder parent = (Folder) destination;
993 copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
997 public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
999 throw new ObjectNotFoundException("No user specified");
1000 if (folderId == null)
1001 throw new ObjectNotFoundException("No folder specified");
1003 throw new ObjectNotFoundException("No destination specified");
1004 if (StringUtils.isEmpty(destName))
1005 throw new ObjectNotFoundException("No destination folder name specified");
1006 Folder folder = dao.getEntityById(Folder.class, folderId);
1007 Folder destination = dao.getEntityById(Folder.class, destId);
1008 User user = dao.getEntityById(User.class, userId);
1009 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1010 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1011 createFolder(user.getId(), destination.getId(), destName);
1015 public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1017 throw new ObjectNotFoundException("No user specified");
1018 if (ownerId == null)
1019 throw new ObjectNotFoundException("No owner specified");
1020 if (folderId == null)
1021 throw new ObjectNotFoundException("No folder specified");
1022 if (StringUtils.isEmpty(dest))
1023 throw new ObjectNotFoundException("No destination specified");
1025 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1026 if (!(destination instanceof Folder))
1027 throw new ObjectNotFoundException("Destination folder not found");
1028 Folder parent = (Folder) destination;
1029 copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1033 public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1035 throw new ObjectNotFoundException("No user specified");
1036 if (folderId == null)
1037 throw new ObjectNotFoundException("No folder specified");
1039 throw new ObjectNotFoundException("No destination specified");
1040 if (StringUtils.isEmpty(destName))
1041 throw new ObjectNotFoundException("No destination folder name specified");
1043 Folder folder = dao.getEntityById(Folder.class, folderId);
1044 Folder destination = dao.getEntityById(Folder.class, destId);
1045 final User user = dao.getEntityById(User.class, userId);
1046 // XXX: quick fix need to copy only visible items to user (Source
1048 if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1050 if(folder.isDeleted())//do not copy trashed folder and contents
1052 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1053 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1054 createFolder(user.getId(), destination.getId(), destName);
1055 Folder createdFolder = dao.getFolder(destination.getId(), destName);
1056 List<FileHeader> files = folder.getFiles();
1058 for (FileHeader file : files)
1059 if(!file.isDeleted())
1060 copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1061 List<Folder> subFolders = folder.getSubfolders();
1062 if (subFolders != null)
1063 for (Folder sub : subFolders)
1064 if(!sub.getId().equals(createdFolder.getId()))
1065 copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1070 * For a provided path, remove the last element and return the rest, that is
1071 * the path of the parent folder.
1073 * @param path the specified path
1074 * @return the path of the parent folder
1075 * @throws ObjectNotFoundException if the provided string contains no path
1078 private String getParentPath(String path) throws ObjectNotFoundException {
1079 int lastDelimiter = path.lastIndexOf('/');
1080 if (lastDelimiter == 0)
1082 if (lastDelimiter == -1)
1084 throw new ObjectNotFoundException("There is no parent in the path: " + path);
1085 else if (lastDelimiter < path.length() - 1)
1086 // Return the part before the delimiter.
1087 return path.substring(0, lastDelimiter);
1089 // Remove the trailing delimiter and then recurse.
1090 String strippedTrail = path.substring(0, lastDelimiter);
1091 return getParentPath(strippedTrail);
1096 * Get the last element in a path that denotes the file or folder name.
1098 * @param path the provided path
1099 * @return the last element in the path
1101 private String getLastElement(String path) {
1102 int lastDelimiter = path.lastIndexOf('/');
1103 if (lastDelimiter == -1)
1106 else if (lastDelimiter < path.length() - 1)
1107 // Return the part after the delimiter.
1108 return path.substring(lastDelimiter + 1);
1110 // Remove the trailing delimiter and then recurse.
1111 String strippedTrail = path.substring(0, lastDelimiter);
1112 return getLastElement(strippedTrail);
1117 public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1119 throw new ObjectNotFoundException("No user specified");
1121 throw new ObjectNotFoundException("No file specified");
1123 // Do the actual work.
1124 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1125 Folder parent = file.getFolder();
1127 throw new ObjectNotFoundException("The specified file has no parent folder");
1128 User user = dao.getEntityById(User.class, userId);
1129 trashFile(user, file);
1130 touchParentFolders(parent, user, new Date());
1133 private void trashFile(User user, FileHeader file) throws InsufficientPermissionsException {
1134 if (!file.hasDeletePermission(user))
1135 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1137 file.setDeleted(true);
1141 public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1143 throw new ObjectNotFoundException("No user specified");
1144 if (ownerId == null)
1145 throw new ObjectNotFoundException("No owner specified");
1147 throw new ObjectNotFoundException("No file specified");
1148 if (StringUtils.isEmpty(dest))
1149 throw new ObjectNotFoundException("No destination specified");
1151 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1152 if (!(destination instanceof Folder))
1153 throw new ObjectNotFoundException("Destination parent folder not found");
1154 Folder parent = (Folder) destination;
1155 moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1159 public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1161 throw new ObjectNotFoundException("No user specified");
1163 throw new ObjectNotFoundException("No file specified");
1165 throw new ObjectNotFoundException("No destination specified");
1166 if (StringUtils.isEmpty(destName))
1167 throw new ObjectNotFoundException("No destination file name specified");
1169 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1170 Folder source = file.getFolder();
1171 Folder destination = dao.getEntityById(Folder.class, destId);
1173 User owner = dao.getEntityById(User.class, userId);
1174 if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1175 throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1177 // if the destination folder belongs to another user:
1178 if (!file.getOwner().equals(destination.getOwner())) {
1179 // (a) check if the destination quota allows the move
1180 if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1181 throw new QuotaExceededException("Not enough free space available");
1182 User newOwner = destination.getOwner();
1183 // (b) if quota OK, change the owner of the file
1184 file.setOwner(newOwner);
1185 // if the file has no permission for the new owner, add it
1186 Permission ownerPermission = null;
1187 for (final Permission p : file.getPermissions())
1188 if (p.getUser() != null)
1189 if (p.getUser().equals(newOwner)) {
1190 ownerPermission = p;
1193 if (ownerPermission == null) {
1194 ownerPermission = new Permission();
1195 ownerPermission.setUser(newOwner);
1196 file.addPermission(ownerPermission);
1198 ownerPermission.setRead(true);
1199 ownerPermission.setWrite(true);
1200 ownerPermission.setModifyACL(true);
1202 // move the file to the destination folder
1203 file.setFolder(destination);
1204 touchParentFolders(source, owner, new Date());
1205 touchParentFolders(destination, owner, new Date());
1209 public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1211 throw new ObjectNotFoundException("No user specified");
1212 if (ownerId == null)
1213 throw new ObjectNotFoundException("No owner specified");
1214 if (folderId == null)
1215 throw new ObjectNotFoundException("No folder specified");
1216 if (StringUtils.isEmpty(dest))
1217 throw new ObjectNotFoundException("No destination specified");
1219 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1220 if (!(destination instanceof Folder))
1221 throw new ObjectNotFoundException("Destination parent folder not found");
1222 Folder parent = (Folder) destination;
1223 moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1227 public void moveFolder(Long userId, Long folderId, Long destId, String destName)
1228 throws ObjectNotFoundException, InsufficientPermissionsException,
1229 QuotaExceededException {
1230 Folder source = dao.getEntityById(Folder.class, folderId);
1231 Folder destination = dao.getEntityById(Folder.class, destId);
1232 User user = dao.getEntityById(User.class, userId);
1233 User sourceOwner = source.getOwner();
1234 User destinationOwner = destination.getOwner();
1235 // Do not move trashed folders and contents.
1236 if (source.isDeleted())
1238 // Check permissions.
1239 if (!destination.hasWritePermission(user)
1240 || !source.hasReadPermission(user)
1241 || !source.hasWritePermission(user))
1242 throw new InsufficientPermissionsException("You don't have the " +
1243 "necessary permissions");
1244 // Use the same timestamp for all subsequent modifications to make
1245 // changes appear simultaneous.
1246 Date now = new Date();
1247 // If source and destination are not in the same user's namespace,
1248 // change owners and check quota.
1249 if (!sourceOwner.equals(destinationOwner)) {
1250 changeOwner(source, destinationOwner, user, now);
1251 if (getQuotaLeft(destinationOwner.getId()) < 0)
1252 throw new QuotaExceededException("Not enough free space " +
1253 "available in destination folder");
1255 // Perform the move.
1256 Folder oldParent = source.getParent();
1257 oldParent.removeSubfolder(source);
1258 destination.addSubfolder(source);
1259 // Mark the former parent and destination trees upwards as modified.
1260 touchParentFolders(oldParent, user, now);
1261 touchParentFolders(source, user, now);
1265 * Recursively change the owner of the specified folder and all of its
1266 * contents to the specified owner. Also mark them all as modified with the
1267 * specified modifier and modificationDate.
1269 private void changeOwner(Folder folder, User owner, User modifier, Date modificationDate) {
1270 for (FileHeader file: folder.getFiles()) {
1271 file.setOwner(owner);
1272 file.getAuditInfo().setModificationDate(modificationDate);
1273 file.getAuditInfo().setModifiedBy(modifier);
1275 for (Folder sub: folder.getSubfolders())
1276 changeOwner(sub, owner, modifier, modificationDate);
1277 folder.setOwner(owner);
1278 folder.getAuditInfo().setModificationDate(modificationDate);
1279 folder.getAuditInfo().setModifiedBy(modifier);
1283 public List<FileHeader> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1286 throw new ObjectNotFoundException("No user specified");
1288 // Do the actual work.
1289 final List<FileHeader> files = dao.getDeletedFiles(userId);
1294 public void removeFileFromTrash(Long userId, Long fileId)
1295 throws ObjectNotFoundException, InsufficientPermissionsException {
1297 throw new ObjectNotFoundException("No user specified");
1299 throw new ObjectNotFoundException("No file specified");
1301 // Do the actual work.
1302 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1303 Folder parent = file.getFolder();
1305 throw new ObjectNotFoundException("The specified file has no parent folder");
1306 User user = dao.getEntityById(User.class, userId);
1307 untrashFile(user, file);
1308 touchParentFolders(parent, user, new Date());
1311 private void untrashFile(User user, FileHeader file) throws InsufficientPermissionsException {
1312 if (!file.hasDeletePermission(user))
1313 throw new InsufficientPermissionsException("User " + user.getUsername() +
1314 " cannot restore file " + file.getName());
1316 file.setDeleted(false);
1320 public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1322 throw new ObjectNotFoundException("No user specified");
1323 if (folderId == null)
1324 throw new ObjectNotFoundException("No folder specified");
1325 Folder folder = dao.getEntityById(Folder.class, folderId);
1326 User user = dao.getEntityById(User.class, userId);
1327 trashFolder(user, folder);
1328 touchParentFolders(folder, user, new Date());
1331 private void trashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException {
1332 if (!folder.hasDeletePermission(user))
1333 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1334 folder.setDeleted(true);
1335 for (FileHeader file : folder.getFiles())
1336 trashFile(user, file);
1337 for (Folder subFolder : folder.getSubfolders())
1338 trashFolder(user, subFolder);
1342 public void removeFolderFromTrash(Long userId, Long folderId)
1343 throws ObjectNotFoundException, InsufficientPermissionsException {
1345 throw new ObjectNotFoundException("No user specified");
1346 if (folderId == null)
1347 throw new ObjectNotFoundException("No folder specified");
1348 Folder folder = dao.getEntityById(Folder.class, folderId);
1349 User user = dao.getEntityById(User.class, userId);
1350 untrashFolder(user, folder);
1351 touchParentFolders(folder, user, new Date());
1354 private void untrashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException {
1355 if (!folder.hasDeletePermission(user))
1356 throw new InsufficientPermissionsException("User " + user.getUsername() +
1357 " cannot restore folder " + folder.getName());
1358 folder.setDeleted(false);
1359 for (FileHeader file : folder.getFiles())
1360 untrashFile(user, file);
1361 for (Folder subFolder : folder.getSubfolders())
1362 untrashFolder(user, subFolder);
1366 public List<Folder> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1367 List<Folder> folders = dao.getDeletedRootFolders(userId);
1372 public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1373 List<Folder> deletedRootFolders = getDeletedRootFolders(userId);
1374 for (Folder folder : deletedRootFolders)
1375 deleteFolder(userId, folder.getId());
1376 List<FileHeader> deletedFiles = getDeletedFiles(userId);
1377 for (FileHeader file : deletedFiles)
1378 deleteFile(userId, file.getId());
1382 public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1383 List<Folder> deletedRootFolders = getDeletedRootFolders(userId);
1384 for (Folder folder : deletedRootFolders)
1385 removeFolderFromTrash(userId, folder.getId());
1386 List<FileHeader> deletedFiles = getDeletedFiles(userId);
1387 for (FileHeader file : deletedFiles)
1388 removeFileFromTrash(userId, file.getId());
1392 public User createUser(String username, String name, String mail,
1393 String idp, String idpid) throws ObjectNotFoundException {
1394 if (username == null)
1395 throw new ObjectNotFoundException("No username specified");
1397 throw new ObjectNotFoundException("No name specified");
1399 User user = new User();
1400 user.setUsername(username);
1402 user.setEmail(mail);
1403 user.setIdentityProvider(idp);
1404 user.setIdentityProviderId(idpid);
1405 Date now = new Date();
1406 AuditInfo auditInfo = new AuditInfo();
1407 auditInfo.setCreationDate(now);
1408 auditInfo.setModificationDate(now);
1409 user.setAuditInfo(auditInfo);
1410 user.setActive(true);
1411 user.generateAuthToken();
1412 user.generateWebDAVPassword();
1413 user.setUserClass(getDefaultUserClass());
1415 // Make sure we get an ID in the user object.
1417 // Create the root folder for the user.
1418 createFolder(user.getName(), null, user);
1423 * Get the default user class, which is the one with the lowest quota.
1425 private UserClass getDefaultUserClass() {
1426 return getUserClasses().get(0);
1430 public List<UserClass> getUserClasses() {
1431 List<UserClass> classes = dao.getUserClasses();
1432 // Create a default user class for first-time use. Afterwards, the
1433 // admin should modify or add to the userclass table.
1434 if (classes.size() == 0) {
1435 UserClass defaultClass = new UserClass();
1436 defaultClass.setName("default");
1437 Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L));
1438 defaultClass.setQuota(defaultQuota);
1439 dao.create(defaultClass);
1440 classes.add(defaultClass);
1446 public User findUserByEmail(String email) {
1447 return dao.findUserByEmail(email);
1451 public void updateUser(User user) {
1456 public User findUser(String username) {
1457 if (username == null)
1459 return dao.findUser(username);
1463 public User updateUserToken(Long userId) throws ObjectNotFoundException {
1465 throw new ObjectNotFoundException("No user specified");
1466 User user = dao.getEntityById(User.class, userId);
1467 user.generateAuthToken();
1472 public Set<Permission> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1474 throw new ObjectNotFoundException("No user specified");
1475 if (folderId == null)
1476 throw new ObjectNotFoundException("No folder specified");
1477 User user = dao.getEntityById(User.class, userId);
1478 Folder folder = dao.getEntityById(Folder.class, folderId);
1479 if(!folder.hasReadPermission(user))
1480 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1481 Set<Permission> perms = folder.getPermissions();
1482 Set<Permission> result = new LinkedHashSet<Permission>();
1483 for (Permission perm : perms)
1484 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1486 for (Permission perm : perms)
1487 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1495 * Set the provided permissions as the new permissions of the specified
1500 * @param permissions
1501 * @throws ObjectNotFoundException
1502 * @throws InsufficientPermissionsException
1504 private void setFolderPermissions(User user, Folder folder, Set<Permission> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1505 if (permissions != null && !permissions.isEmpty()) {
1506 User owner = folder.getOwner();
1507 Permission ownerPerm = null;
1508 for (Permission perm : permissions)
1509 if (perm.getUser() != null && perm.getUser().getId().equals(owner.getId())) {
1513 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1514 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1515 // Delete previous entries
1516 for (Permission perm: folder.getPermissions())
1518 folder.getPermissions().clear();
1519 for (Permission p : permissions) {
1520 // Skip 'empty' permission entries.
1521 if (!p.getRead() && !p.getWrite() && !p.getModifyACL()) continue;
1522 folder.addPermission(getPermission(p));
1525 for (FileHeader file : folder.getFiles()) {
1526 setFilePermissions(file, permissions);
1527 Date now = new Date();
1528 file.getAuditInfo().setModificationDate(now);
1529 file.getAuditInfo().setModifiedBy(user);
1531 for (Folder sub : folder.getSubfolders())
1532 setFolderPermissions(user, sub, permissions);
1536 private Permission getPermission(Permission perm) throws ObjectNotFoundException {
1537 Permission res = new Permission();
1538 if (perm.getGroup() != null)
1539 res.setGroup(dao.getEntityById(Group.class, perm.getGroup().getId()));
1540 else if (perm.getUser() != null)
1541 if (perm.getUser().getId() == null)
1542 res.setUser(dao.getUser(perm.getUser().getUsername()));
1544 res.setUser(dao.getEntityById(User.class, perm.getUser().getId()));
1545 res.setRead(perm.hasRead());
1546 res.setWrite(perm.hasWrite());
1547 res.setModifyACL(perm.hasModifyACL());
1552 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1555 public List<User> getUsersByUserNameLike(String username) {
1556 List<User> users = dao.getUsersByUserNameLike(username);
1562 public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1564 throw new ObjectNotFoundException("No user specified");
1565 if (groupId == null)
1566 throw new ObjectNotFoundException("No group specified");
1567 if (userToAddId == null)
1568 throw new ObjectNotFoundException("No user to add specified");
1569 User user = dao.getEntityById(User.class, userId);
1570 Group group = dao.getEntityById(Group.class, groupId);
1571 if (!group.getOwner().equals(user))
1572 throw new InsufficientPermissionsException();
1573 User userToAdd = dao.getEntityById(User.class, userToAddId);
1574 if (group.contains(userToAdd))
1575 throw new DuplicateNameException("User already exists in group");
1576 group.getMembers().add(userToAdd);
1582 public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1584 throw new ObjectNotFoundException("No user specified");
1585 User user = dao.getEntityById(User.class, userId);
1586 user.invalidateAuthToken();
1591 public List<Folder> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1593 throw new ObjectNotFoundException("No user specified");
1594 List<Folder> folders = dao.getSharedRootFolders(userId);
1595 List<Folder> result = new ArrayList<Folder>();
1596 for (Folder f : folders) {
1598 lf.setSubfolders(getSharedSubfolders(userId, f.getId()));
1605 public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1607 throw new ObjectNotFoundException("No user specified");
1608 if (groupId == null)
1609 throw new ObjectNotFoundException("No group specified");
1610 if (memberId == null)
1611 throw new ObjectNotFoundException("No member specified");
1612 User owner = dao.getEntityById(User.class, userId);
1613 Group group = dao.getEntityById(Group.class, groupId);
1614 User member = dao.getEntityById(User.class, memberId);
1615 if (!group.getOwner().equals(owner))
1616 throw new InsufficientPermissionsException("User is not the owner of the group");
1617 group.removeMemberFromGroup(member);
1623 public List<User> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1624 List<User> users = dao.getUsersSharingFoldersForUser(userId);
1625 List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1626 List<User> result = new ArrayList<User>();
1627 for (User u : users)
1629 for(User fu : usersFiles)
1630 if(!users.contains(fu))
1636 public Set<Permission> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1638 throw new ObjectNotFoundException("No user specified");
1640 throw new ObjectNotFoundException("No folder specified");
1641 User user = dao.getEntityById(User.class, userId);
1642 FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1643 if(!folder.hasReadPermission(user))
1644 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1645 Set<Permission> perms = folder.getPermissions();
1646 Set<Permission> result = new LinkedHashSet<Permission>();
1647 for (Permission perm : perms)
1648 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1650 for (Permission perm : perms)
1651 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1658 * Set the provided permissions as the new permissions of the specified
1659 * file. This method sets the modification date/user attributes to the
1660 * current values as a side effect.
1663 * @param permissions
1664 * @throws ObjectNotFoundException
1665 * @throws InsufficientPermissionsException
1667 private void setFilePermissions(FileHeader file,
1668 Set<Permission> permissions)
1669 throws ObjectNotFoundException, InsufficientPermissionsException {
1670 if (permissions != null && !permissions.isEmpty()) {
1671 Permission ownerPerm = null;
1672 for (Permission perm : permissions)
1673 if (perm.getUser() != null && perm.getUser().getId().equals(file.getOwner().getId())) {
1677 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1678 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1679 // Delete previous entries.
1680 for (Permission perm: file.getPermissions())
1682 file.getPermissions().clear();
1683 for (Permission perm : permissions) {
1684 // Skip 'empty' permission entries.
1685 if (!perm.getRead() && !perm.getWrite() && !perm.getModifyACL()) continue;
1686 file.addPermission(getPermission(perm));
1693 public List<FileHeader> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1695 throw new ObjectNotFoundException("No user specified");
1696 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1701 public List<FileHeader> getSharedFiles(Long userId) throws ObjectNotFoundException {
1703 throw new ObjectNotFoundException("No user specified");
1704 List<FileHeader> files = dao.getSharedFiles(userId);
1709 public List<Folder> getSharedFolders(Long userId) throws ObjectNotFoundException {
1711 throw new ObjectNotFoundException("No user specified");
1712 List<Folder> folders = dao.getSharedFolders(userId);
1717 public List<FileHeader> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1718 if (ownerId == null)
1719 throw new ObjectNotFoundException("No owner specified");
1720 if (callingUserId == null)
1721 throw new ObjectNotFoundException("No calling user specified");
1722 List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1727 public List<Folder> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1728 if (ownerId == null)
1729 throw new ObjectNotFoundException("No owner specified");
1730 if (callingUserId == null)
1731 throw new ObjectNotFoundException("No calling user specified");
1732 List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1733 List<Folder> result = new ArrayList<Folder>();
1734 for (Folder f : folders) {
1736 lf.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1744 public List<Folder> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1746 throw new ObjectNotFoundException("No user specified");
1747 if (folderId == null)
1748 throw new ObjectNotFoundException("No folder specified");
1749 User user = dao.getEntityById(User.class, userId);
1750 Folder folder = dao.getEntityById(Folder.class, folderId);
1751 List<Folder> result = new ArrayList<Folder>();
1752 if (folder.isShared(user) || folder.isReadForAll())
1753 for (Folder f : folder.getSubfolders())
1754 if ((f.isShared(user) || f.isReadForAll()) && !f.isDeleted())
1760 public List<Folder> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1762 throw new ObjectNotFoundException("No user specified");
1763 if (callingUserId == null)
1764 throw new ObjectNotFoundException("No user specified");
1765 if (folderId == null)
1766 throw new ObjectNotFoundException("No folder specified");
1767 User user = dao.getEntityById(User.class, callingUserId);
1768 Folder folder = dao.getEntityById(Folder.class, folderId);
1769 List<Folder> result = new ArrayList<Folder>();
1770 if (folder.isSharedForOtherUser(user))
1771 for (Folder f : folder.getSubfolders())
1772 if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1774 lf.setSubfolders(getSharedSubfolders(userId, callingUserId, lf.getId()));
1782 public List<FileHeader> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1783 long startTime = System.currentTimeMillis();
1785 throw new ObjectNotFoundException("No user specified");
1786 User user = getUser(userId);
1788 throw new ObjectNotFoundException("No query specified");
1789 List<FileHeader> files = search(user.getId(), query);
1791 long stopTime = System.currentTimeMillis();
1792 logger.info("Total time: " + (stopTime - startTime));
1797 * Performs the actuals search on the solr server and returns the results
1801 * @return a List of FileHeader objects
1803 private List<FileHeader> search(Long userId, String query) {
1804 final int maxRows = 100;
1805 List<FileHeader> result = new ArrayList<FileHeader>();
1807 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
1808 List<Group> groups = dao.getGroupsContainingUser(userId);
1809 String constructedQuery = escapeCharacters(normalizeSearchQuery(query)) + " AND (public: true OR ureaders: " + userId;
1810 if (!groups.isEmpty()) {
1811 constructedQuery += " OR (";
1812 for (int i=0; i<groups.size(); i++) {
1813 Group g = groups.get(i);
1814 constructedQuery += "greaders :" + g.getId();
1815 if (i < groups.size() - 1)
1816 constructedQuery += " OR ";
1818 constructedQuery += ")";
1820 constructedQuery += ")";
1821 SolrQuery solrQuery = new SolrQuery(constructedQuery);
1822 solrQuery.setRows(maxRows);
1823 long startTime = System.currentTimeMillis();
1824 QueryResponse response = solr.query(solrQuery);
1825 SolrDocumentList results = response.getResults();
1826 if (results.getNumFound() > maxRows) {
1827 solrQuery.setRows(Integer.valueOf((int) results.getNumFound()));
1828 response = solr.query(solrQuery);
1829 results = response.getResults();
1831 long stopTime = System.currentTimeMillis();
1832 logger.info("Search time:" + (stopTime - startTime));
1833 User user = getUser(userId);
1834 startTime = System.currentTimeMillis();
1835 for (SolrDocument d : results) {
1836 Long id = Long.valueOf((String) d.getFieldValue("id"));
1838 FileHeader f = dao.getEntityById(FileHeader.class, id);
1840 } catch (ObjectNotFoundException e) {
1841 logger.warn("Search result id " + id + " cannot be found", e);
1844 stopTime = System.currentTimeMillis();
1845 logger.info("File loads: " + (stopTime - startTime));
1846 } catch (MalformedURLException e) {
1848 throw new EJBException(e);
1849 } catch (SolrServerException e) {
1851 throw new EJBException(e);
1852 } catch (ObjectNotFoundException e) {
1854 throw new EJBException(e);
1860 public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1861 for(Long l : fileIds){
1862 FileHeader file = dao.getEntityById(FileHeader.class, l);
1863 copyFile(userId, l, destId, file.getName());
1870 public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1871 for(Long l : fileIds){
1872 FileHeader file = dao.getEntityById(FileHeader.class, l);
1873 moveFile(userId, l, destId, file.getName());
1879 public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1881 throw new ObjectNotFoundException("No user specified");
1882 User user = dao.getEntityById(User.class, userId);
1883 Nonce nonce = Nonce.createNonce(user.getId());
1889 public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1891 throw new ObjectNotFoundException("No user specified");
1893 throw new ObjectNotFoundException("No nonce specified");
1894 return dao.getNonce(nonce, userId);
1898 public void removeNonce(Long id) throws ObjectNotFoundException {
1900 throw new ObjectNotFoundException("No nonce specified");
1901 Nonce nonce = dao.getEntityById(Nonce.class, id);
1906 public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1908 throw new ObjectNotFoundException("No user specified");
1909 User user = dao.getEntityById(User.class, userId);
1910 user.setNonce(nonce);
1911 user.setNonceExpiryDate(nonceExpiryDate);
1915 public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1917 throw new ObjectNotFoundException("No user specified");
1918 StatsDTO stats = new StatsDTO();
1919 stats.setFileCount(dao.getFileCount(userId));
1920 Long fileSize = dao.getFileSize(userId);
1921 stats.setFileSize(fileSize);
1922 Long quota = getQuota(userId);
1923 Long quotaLeft = quota - fileSize;
1924 stats.setQuotaLeftSize(quotaLeft);
1929 public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1931 throw new ObjectNotFoundException("No user specified");
1933 throw new ObjectNotFoundException("No file specified");
1934 User user = dao.getEntityById(User.class, userId);
1935 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1936 if(!header.hasWritePermission(user))
1937 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1938 FileBody body = dao.getFileVersion(fileId, version);
1939 final File fileContents = new File(body.getStoredFilePath());
1942 updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
1943 } catch (FileNotFoundException e) {
1944 throw new GSSIOException(e);
1950 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
1953 public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1955 throw new ObjectNotFoundException("No user specified");
1957 throw new ObjectNotFoundException("No file specified");
1958 User user = dao.getEntityById(User.class, userId);
1959 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1960 if(!header.hasWritePermission(user))
1961 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1962 Iterator<FileBody> it = header.getBodies().iterator();
1963 while(it.hasNext()){
1964 FileBody body = it.next();
1965 if(!body.equals(header.getCurrentBody())){
1966 deleteActualFile(body.getStoredFilePath());
1971 header.getCurrentBody().setVersion(1);
1973 Folder parent = header.getFolder();
1974 touchParentFolders(parent, user, new Date());
1978 * Gets the quota left for specified user ID.
1980 private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
1981 Long fileSize = dao.getFileSize(userId);
1982 Long quota = getQuota(userId);
1983 return quota - fileSize;
1987 * Gets the quota for specified user ID.
1989 private Long getQuota(Long userId) throws ObjectNotFoundException{
1990 UserClass uc = getUser(userId).getUserClass();
1992 uc = getDefaultUserClass();
1993 return uc.getQuota();
1997 @TransactionAttribute(TransactionAttributeType.NEVER)
1998 public String rebuildSolrIndex() {
2000 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2001 solr.deleteByQuery("*:*");
2003 logger.info("Deleted everything in solr");
2005 List<Long> fileIds = dao.getAllFileIds();
2006 logger.info("Total of " + fileIds.size() + " will be indexed");
2008 for (Long id : fileIds) {
2009 postFileToSolr(solr, id);
2013 logger.info("Sent commit to solr at file " + i);
2018 logger.info("Finished indexing of " + i + " files");
2019 return "Finished indexing of " + i + " files";
2020 } catch (IOException e) {
2021 throw new EJBException(e);
2022 } catch (SolrServerException e) {
2023 throw new EJBException(e);
2028 @TransactionAttribute(TransactionAttributeType.NEVER)
2029 public String refreshSolrIndex() {
2031 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2033 List<Long> fileIds = dao.getAllFileIds();
2034 logger.info("Total of " + fileIds.size() + " will be indexed");
2036 for (Long id : fileIds) {
2037 postFileToSolr(solr, id);
2042 logger.info("Sent commit to solr at file " + i);
2046 logger.info("Finished indexing of " + i + " files");
2047 return "Finished indexing of " + i + " files";
2048 } catch (IOException e) {
2049 throw new EJBException(e);
2050 } catch (SolrServerException e) {
2051 throw new EJBException(e);
2056 public FileHeader createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2057 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2058 InsufficientPermissionsException, QuotaExceededException {
2061 throw new ObjectNotFoundException("No user specified");
2062 if (folderId == null)
2063 throw new ObjectNotFoundException("No folder specified");
2064 String contentType = mimeType;
2065 if (StringUtils.isEmpty(mimeType))
2066 contentType = DEFAULT_MIME_TYPE;
2067 if (StringUtils.isEmpty(name))
2068 throw new ObjectNotFoundException("No file name specified");
2069 if (dao.existsFolderOrFile(folderId, name))
2070 throw new DuplicateNameException("A folder or file with the name '" + name +
2071 "' already exists at this level");
2073 // Do the actual work.
2074 Folder parent = null;
2076 parent = dao.getEntityById(Folder.class, folderId);
2077 } catch (final ObjectNotFoundException onfe) {
2078 // Supply a more accurate problem description.
2079 throw new ObjectNotFoundException("Parent folder not found");
2081 final User owner = dao.getEntityById(User.class, userId);
2082 if (!parent.hasWritePermission(owner))
2083 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2084 final FileHeader file = new FileHeader();
2086 parent.addFile(file);
2087 // set file owner to folder owner
2088 file.setOwner(parent.getOwner());
2089 //set file's readForAll value according to parent folder readForAll value
2090 file.setReadForAll(parent.isReadForAll());
2092 final Date now = new Date();
2093 final AuditInfo auditInfo = new AuditInfo();
2094 auditInfo.setCreatedBy(owner);
2095 auditInfo.setCreationDate(now);
2096 auditInfo.setModifiedBy(owner);
2097 auditInfo.setModificationDate(now);
2098 file.setAuditInfo(auditInfo);
2099 // TODO set the proper versioning flag on creation
2100 file.setVersioned(false);
2102 for (final Permission p : parent.getPermissions()) {
2103 final Permission permission = new Permission();
2104 permission.setGroup(p.getGroup());
2105 permission.setUser(p.getUser());
2106 permission.setRead(p.getRead());
2107 permission.setWrite(p.getWrite());
2108 permission.setModifyACL(p.getModifyACL());
2109 file.addPermission(permission);
2112 // Create the file body.
2114 createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2115 } catch (FileNotFoundException e) {
2116 throw new GSSIOException(e);
2118 touchParentFolders(parent, owner, new Date());
2120 indexFile(file.getId(), false);
2126 public FileHeader updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2128 throw new ObjectNotFoundException("No user specified");
2130 throw new ObjectNotFoundException("No file specified");
2131 String contentType = mimeType;
2133 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2135 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2136 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2137 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2138 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2139 contentType = identifyMimeType(file.getName());
2141 final User owner = dao.getEntityById(User.class, userId);
2142 if (!file.hasWritePermission(owner))
2143 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2144 final Date now = new Date();
2145 final AuditInfo auditInfo = new AuditInfo();
2146 auditInfo.setCreatedBy(owner);
2147 auditInfo.setCreationDate(now);
2148 auditInfo.setModifiedBy(owner);
2149 auditInfo.setModificationDate(now);
2151 createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2152 } catch (FileNotFoundException e) {
2153 throw new GSSIOException(e);
2155 Folder parent = file.getFolder();
2156 touchParentFolders(parent, owner, new Date());
2158 indexFile(fileId, false);
2163 * Helper method for identifying mime type by examining the filename extension
2166 * @return the mime type
2168 private String identifyMimeType(String filename) {
2169 if (filename.indexOf('.') != -1) {
2170 String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2171 if (".doc".equals(extension))
2172 return "application/msword";
2173 else if (".xls".equals(extension))
2174 return "application/vnd.ms-excel";
2175 else if (".ppt".equals(extension))
2176 return "application/vnd.ms-powerpoint";
2177 else if (".pdf".equals(extension))
2178 return "application/pdf";
2179 else if (".gif".equals(extension))
2181 else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2182 return "image/jpeg";
2183 else if (".tiff".equals(extension) || ".tif".equals(extension))
2184 return "image/tiff";
2185 else if (".png".equals(extension))
2187 else if (".bmp".equals(extension))
2190 // when all else fails assign the default mime type
2191 return DEFAULT_MIME_TYPE;
2195 * Helper method to create a new file body and attach it as the current body
2196 * of the provided file header.
2198 * @param name the original file name
2199 * @param mimeType the content type
2200 * @param fileSize the uploaded file size
2201 * @param filePath the uploaded file full path
2202 * @param header the file header that will be associated with the new body
2203 * @param auditInfo the audit info
2204 * @throws FileNotFoundException
2205 * @throws QuotaExceededException
2206 * @throws ObjectNotFoundException if the owner was not found
2208 private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2209 FileHeader header, AuditInfo auditInfo)
2210 throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2212 long currentTotalSize = 0;
2213 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2214 currentTotalSize = header.getTotalSize();
2215 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2216 if(quotaLeft < fileSize-currentTotalSize) {
2217 // quota exceeded -> delete the file
2218 deleteActualFile(filePath);
2219 throw new QuotaExceededException("Not enough free space available");
2222 FileBody body = new FileBody();
2224 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2225 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2226 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2227 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2228 body.setMimeType(identifyMimeType(name));
2230 body.setMimeType(mimeType);
2231 body.setAuditInfo(auditInfo);
2232 body.setFileSize(fileSize);
2233 body.setOriginalFilename(name);
2234 body.setStoredFilePath(filePath);
2235 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2236 if(!header.isVersioned() && header.getCurrentBody() != null){
2237 header.setCurrentBody(null);
2238 if (header.getBodies() != null) {
2239 Iterator<FileBody> it = header.getBodies().iterator();
2240 while(it.hasNext()){
2241 FileBody bo = it.next();
2242 deleteActualFile(bo.getStoredFilePath());
2250 header.addBody(body);
2251 header.setAuditInfo(auditInfo);
2258 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2259 public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2261 throw new ObjectNotFoundException("No user specified");
2262 User owner = dao.getEntityById(User.class, userId);
2264 throw new ObjectNotFoundException("No user specified");
2265 long start = 0, end = 0;
2266 if (logger.isDebugEnabled())
2267 start = System.currentTimeMillis();
2268 File result = new File(generateRepositoryFilePath());
2270 final FileOutputStream output = new FileOutputStream(result);
2271 final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2274 while (-1 != (n = stream.read(buffer)))
2275 output.write(buffer, 0, n);
2278 } catch (IOException e) {
2279 if (!result.delete())
2280 logger.warn("Could not delete " + result.getPath());
2283 if (logger.isDebugEnabled()) {
2284 end = System.currentTimeMillis();
2285 logger.debug("Time to upload: " + (end - start) + " (msec)");
2292 public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2295 throw new ObjectNotFoundException("No user specified");
2296 User user = dao.getEntityById(User.class, userId);
2297 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2299 status = new FileUploadStatus();
2300 status.setOwner(user);
2301 status.setFilename(filename);
2302 status.setBytesUploaded(bytesTransfered);
2303 status.setFileSize(fileSize);
2307 status.setBytesUploaded(bytesTransfered);
2308 status.setFileSize(fileSize);
2315 public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2317 throw new ObjectNotFoundException("No user specified");
2318 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2324 public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2325 return dao.getFileUploadStatus(userId, fileName);
2329 public FileBody getFileVersion(Long userId, Long fileId, int version)
2330 throws ObjectNotFoundException, InsufficientPermissionsException {
2332 throw new ObjectNotFoundException("No user specified");
2334 throw new ObjectNotFoundException("No file specified");
2336 throw new ObjectNotFoundException("No valid version specified");
2337 User user = dao.getEntityById(User.class, userId);
2338 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2339 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2340 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2341 FileBody body = dao.getFileVersion(fileId, version);
2346 public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2348 throw new ObjectNotFoundException("No user specified");
2349 User user = dao.getEntityById(User.class, userId);
2350 user.setAcceptedPolicy(isAccepted);
2355 public void updateAccounting(User user, Date date, long bandwidthDiff) {
2356 dao.updateAccounting(user, date, bandwidthDiff);
2360 public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2362 throw new ObjectNotFoundException("No user specified");
2363 if (folderId == null)
2364 throw new ObjectNotFoundException("No folder specified");
2365 User user = dao.getEntityById(User.class, userId);
2366 Folder folder = dao.getEntityById(Folder.class, folderId);
2367 // Check permissions
2368 if (!folder.hasReadPermission(user))
2374 public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2376 throw new ObjectNotFoundException("No user specified");
2377 User user = dao.getEntityById(User.class, userId);
2378 user.generateWebDAVPassword();
2379 return user.getWebDAVPassword();
2383 public Invitation findInvite(String code) {
2386 return dao.findInvite(code);
2390 public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2391 LDAPConnection lc = new LDAPConnection();
2392 LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2393 attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2394 attributeSet.add(new LDAPAttribute("uid", username));
2395 attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2396 attributeSet.add(new LDAPAttribute("sn", lastname));
2397 attributeSet.add(new LDAPAttribute("givenName", firstname));
2398 attributeSet.add(new LDAPAttribute("mail", email));
2399 attributeSet.add(new LDAPAttribute("userPassword", password));
2400 String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2401 LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2403 lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2404 lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2405 getConfiguration().getString("bindPassword").getBytes("UTF8"));
2407 logger.info("Successfully added LDAP account: " + dn);
2409 } catch(LDAPException e) {
2410 throw new RuntimeException(e);
2411 } catch(UnsupportedEncodingException e) {
2412 throw new RuntimeException(e);
2418 public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2419 User user = findUser(username);
2421 throw new ObjectNotFoundException("The user was not found");
2422 Invitation invite = findInvite(code);
2423 if (invite.getUser() != null)
2424 throw new InvitationUsedException("This code has already been used");
2425 invite.setUser(user);
2426 UserClass couponClass = getCouponUserClass();
2427 user.setUserClass(couponClass);
2432 public UserClass getCouponUserClass() {
2433 return dao.findCouponUserClass();
2437 * Set the provided readForAll as the new readforAll value of the specified
2438 * folder and sub-folders.
2443 * @throws ObjectNotFoundException
2446 private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){
2447 if (readForAll != null && user.equals(folder.getOwner())){
2448 folder.setReadForAll(readForAll);
2450 for (FileHeader file : folder.getFiles())
2451 file.setReadForAll(readForAll);
2453 //only update subfolders when readforall is true. otherwise all sub-folders stay untouched
2454 for (Folder sub : folder.getSubfolders())
2455 setFolderReadForAll(user, sub, readForAll);
2462 * Update the userLogin with the values from the supplied object.
2465 public void addUserLogin(UserLogin userLogin) {
2466 dao.update(userLogin);
2471 * Retrieves the current session user login and the user's last login
2474 * @return a list of last two user logins
2475 * @throws ObjectNotFoundException
2478 public List<UserLogin> getLastUserLogins(Long userId) throws ObjectNotFoundException{
2479 List<UserLogin> userLoginResults = new ArrayList<UserLogin>();
2480 userLoginResults = dao.getLoginsForUser(userId);
2481 if(userLoginResults.size() == 0)
2482 throw new ObjectNotFoundException("No userlogin found for the user");
2483 //if the user logins for the first time lastLoginDate = currentLoginDate
2484 if(userLoginResults.size()==1)
2485 userLoginResults.add(userLoginResults.get(0));
2486 return userLoginResults;
2491 public void postFileToSolr(CommonsHttpSolrServer solr, Long id) {
2493 FileHeader file = dao.getFileForIndexing(id);
2494 FileBody body = file.getCurrentBody();
2495 String mime = body.getMimeType();
2496 boolean multipart = true;
2497 if (!mime.equals("application/pdf")
2498 && !mime.equals("text/plain")
2499 && !mime.equals("text/html")
2500 && !mime.endsWith("msword")
2501 && !mime.endsWith("ms-excel")
2502 && !mime.endsWith("powerpoint")
2503 || (body.getFileSize() > getConfiguration().getLong("solrDocumentUploadLimitInKB") * 1024))
2507 sendMetaDataOnly(solr, file);
2509 ContentStreamUpdateRequest solrRequest = new ContentStreamUpdateRequest(getConfiguration().getString("solr.rich.update.path"));
2510 solrRequest.setParam("literal.id", file.getId().toString());
2511 solrRequest.setParam("literal.name", file.getName());
2512 for (FileTag t : file.getFileTags()) {
2513 solrRequest.getParams().add("literal.tag", t.getTag());
2515 for (Permission p : file.getPermissions()) {
2517 if (p.getUser() != null)
2518 solrRequest.setParam("literal.ureaders", p.getUser().getId().toString());
2519 else if (p.getGroup() != null)
2520 solrRequest.setParam("literal.greaders", p.getGroup().getId().toString());
2523 solrRequest.setParam("literal.owner", file.getOwner().getId().toString());
2524 solrRequest.setParam("literal.public", String.valueOf(file.isReadForAll()));
2525 File fsFile = new File(body.getStoredFilePath());
2526 solrRequest.addFile(fsFile);
2528 solr.request(solrRequest);
2530 catch (SolrException e) {
2531 logger.warn("File " + id + " failed with SolrException: " + e.getLocalizedMessage() + ". Retrying without the file");
2532 //Let 's try without the file
2533 sendMetaDataOnly(solr, file);
2535 catch (NullPointerException e) {
2536 logger.warn("File " + id + " failed with NullPointerException: " + e.getLocalizedMessage() + ". Retrying without the file");
2537 //Let 's try without the file
2538 sendMetaDataOnly(solr, file);
2540 catch (SolrServerException e) {
2541 logger.warn("File " + id + " failed with SolrServerException: " + e.getLocalizedMessage() + ". Retrying without the file");
2542 //Let 's try without the file
2543 sendMetaDataOnly(solr, file);
2546 } catch (MalformedURLException e) {
2547 throw new EJBException(e);
2548 } catch (ObjectNotFoundException e) {
2549 logger.error("Indexing of file id " + id + " failed.", e);
2550 } catch (SolrServerException e) {
2551 throw new EJBException(e);
2552 } catch (IOException e) {
2553 throw new EJBException(e);
2557 private void sendMetaDataOnly(CommonsHttpSolrServer solr, FileHeader file) throws SolrServerException, IOException {
2558 SolrInputDocument solrDoc = new SolrInputDocument();
2559 solrDoc.addField("id", file.getId().toString());
2560 solrDoc.addField("name", file.getName());
2561 for (FileTag t : file.getFileTags()) {
2562 solrDoc.addField("tag", t.getTag());
2564 for (Permission p : file.getPermissions()) {
2566 if (p.getUser() != null)
2567 solrDoc.addField("ureaders", p.getUser().getId());
2568 else if (p.getGroup() != null)
2569 solrDoc.addField("greaders", p.getGroup().getId());
2572 solrDoc.addField("owner", file.getOwner().getId());
2573 solrDoc.addField("public", file.isReadForAll());
2577 private String tokenizeFilename(String filename){
2578 StringBuffer result = new StringBuffer();
2579 StringTokenizer tokenizer = new StringTokenizer(filename,"._");
2580 while(tokenizer.hasMoreTokens()){
2581 result.append(tokenizer.nextToken());
2584 result.append(filename);
2585 return result.toString();
2588 private String normalizeSearchQuery(String query) {
2589 if (query.contains("*"))
2590 return query.toLowerCase().replace('ά', 'α').replace('έ', 'ε').replace('ί', 'ι').replace('ή', 'η').replace('ύ', 'υ')
2591 .replace('ό', 'ο').replace('ς', 'σ').replace('ώ', 'ω').replace('ϊ', 'ι').replace('ϋ', 'υ');
2596 private String escapeCharacters(String text) {
2597 return text.replaceAll(":", "\\\\:");
2600 /*** NEW METHODS IN ORDER TO AVOID LAZY loading exception in json render
2603 public Folder expandFolder(Folder folder) throws ObjectNotFoundException{
2604 Folder result = dao.getEntityById(Folder.class, folder.getId());
2605 result.getSubfolders().size();
2606 result.getFiles().size();
2607 result.getPermissions().size();
2612 public FileHeader expandFile(FileHeader folder) throws ObjectNotFoundException{
2613 FileHeader result = dao.getEntityById(FileHeader.class, folder.getId());
2615 result.getPermissions().size();
2616 result.getFileTags().size();
2621 public Group expandGroup(Group folder) throws ObjectNotFoundException{
2622 Group result = dao.getEntityById(Group.class, folder.getId());
2623 result.getMembers().size();