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.SolrServerException;
90 import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
91 import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
92 import org.apache.solr.client.solrj.response.QueryResponse;
93 import org.apache.solr.common.SolrDocument;
94 import org.apache.solr.common.SolrDocumentList;
95 import org.apache.solr.common.SolrException;
96 import org.apache.solr.common.SolrInputDocument;
97 import org.hibernate.exception.ConstraintViolationException;
99 import com.novell.ldap.LDAPAttribute;
100 import com.novell.ldap.LDAPAttributeSet;
101 import com.novell.ldap.LDAPConnection;
102 import com.novell.ldap.LDAPEntry;
103 import com.novell.ldap.LDAPException;
106 * The concrete implementation of the ExternalAPI interface.
111 public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
113 * The default MIME type for files without an explicit one.
115 private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
118 * The size of the buffer that is used to temporarily store chunks of
119 * uploaded files, while storing them to the file repository.
121 private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
126 private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
129 * Injected reference to the GSSDAO data access facade.
136 * A cached random number generator for creating unique filenames.
138 private static Random random = new Random();
141 * Mark the folder and all of its parent folders as modified from the specified user.
143 private void touchParentFolders(Folder folder, User user, Date date) {
146 AuditInfo ai = f.getAuditInfo();
147 ai.setModifiedBy(user);
148 ai.setModificationDate(date);
154 private Long getRootFolderId(Long userId) throws ObjectNotFoundException {
156 throw new ObjectNotFoundException("No user specified");
157 return dao.getRootFolderId(userId);
161 public Folder getRootFolder(Long userId) throws ObjectNotFoundException {
163 throw new ObjectNotFoundException("No user specified");
164 Folder folder = dao.getRootFolder(userId);
169 public Folder getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
171 throw new ObjectNotFoundException("No user specified");
172 if (folderId == null)
173 throw new ObjectNotFoundException("No folder specified");
174 final User user = dao.getEntityById(User.class, userId);
175 final Folder folder = dao.getEntityById(Folder.class, folderId);
177 if (!folder.hasReadPermission(user))
178 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
179 return expandFolder(folder);
183 public User getUser(Long userId) throws ObjectNotFoundException {
185 throw new ObjectNotFoundException("No user specified");
186 return dao.getEntityById(User.class, userId);
190 public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
191 return getUser(userId).getDTO();
195 public Group getGroup(final Long groupId) throws ObjectNotFoundException {
197 throw new ObjectNotFoundException("No group specified");
198 final Group group = dao.getEntityById(Group.class, groupId);
203 public Group getGroup(Long userId, String name) throws ObjectNotFoundException {
205 throw new ObjectNotFoundException("No user specified");
207 throw new ObjectNotFoundException("No group specified");
208 User user = dao.getEntityById(User.class, userId);
209 List<Group> groups = user.getGroupsSpecified();
210 for (Group group: groups)
211 if (group.getName().equals(name))
213 throw new ObjectNotFoundException("Group " + name + " not found");
217 public List<Group> getGroups(final Long userId) throws ObjectNotFoundException {
219 throw new ObjectNotFoundException("No user specified");
220 final List<Group> groups = dao.getGroups(userId);
225 public List<FileHeader> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
226 throws ObjectNotFoundException, InsufficientPermissionsException {
229 throw new ObjectNotFoundException("No user specified");
230 if (folderId == null)
231 throw new ObjectNotFoundException("No folder specified");
232 User user = dao.getEntityById(User.class, userId);
233 Folder folder = dao.getEntityById(Folder.class, folderId);
234 if (!folder.hasReadPermission(user))
235 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
236 List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
241 public List<User> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
244 throw new ObjectNotFoundException("No user specified");
246 throw new ObjectNotFoundException("No group specified");
248 // Do the actual work.
249 final List<User> users = dao.getUsers(groupId);
254 public Folder createFolder(Long userId, Long parentId, String name)
255 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
258 throw new ObjectNotFoundException("No user specified");
259 if (StringUtils.isEmpty(name))
260 throw new ObjectNotFoundException("New folder name is empty");
261 if (parentId == null)
262 throw new ObjectNotFoundException("No parent specified");
263 if (dao.existsFolderOrFile(parentId, name))
264 throw new DuplicateNameException("A folder or file with the name '" +
265 name + "' already exists at this level");
267 User creator = dao.getEntityById(User.class, userId);
269 Folder parent = null;
271 parent = dao.getEntityById(Folder.class, parentId);
272 } catch (ObjectNotFoundException onfe) {
273 // Supply a more accurate problem description.
274 throw new ObjectNotFoundException("Parent folder not found");
276 if (!parent.hasWritePermission(creator))
277 throw new InsufficientPermissionsException("You don't have the permissions" +
278 " to write to this folder");
280 // Do the actual work.
281 return createFolder(name, parent, creator);
285 * Create a new folder with the provided name, parent and owner.
290 * @return the new folder
292 private Folder createFolder(String name, Folder parent, User creator) {
293 Folder folder = new Folder();
294 folder.setName(name);
295 if (parent != null) {
296 parent.addSubfolder(folder);
297 folder.setOwner(parent.getOwner());
299 folder.setOwner(creator);
301 Date now = new Date();
302 AuditInfo auditInfo = new AuditInfo();
303 auditInfo.setCreatedBy(creator);
304 auditInfo.setCreationDate(now);
305 auditInfo.setModifiedBy(creator);
306 auditInfo.setModificationDate(now);
307 folder.setAuditInfo(auditInfo);
308 touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
311 for (Permission p : parent.getPermissions()) {
312 Permission permission = new Permission();
313 permission.setGroup(p.getGroup());
314 permission.setUser(p.getUser());
315 permission.setRead(p.getRead());
316 permission.setWrite(p.getWrite());
317 permission.setModifyACL(p.getModifyACL());
318 folder.addPermission(permission);
321 Permission permission = new Permission();
322 permission.setUser(creator);
323 permission.setRead(true);
324 permission.setWrite(true);
325 permission.setModifyACL(true);
326 folder.addPermission(permission);
330 folder.setReadForAll(parent.isReadForAll());
337 public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
340 throw new ObjectNotFoundException("No user specified");
341 if (folderId == null)
342 throw new ObjectNotFoundException("No folder specified");
344 // Do the actual work.
345 final Folder folder = dao.getEntityById(Folder.class, folderId);
346 final Folder parent = folder.getParent();
348 throw new ObjectNotFoundException("Deleting the root folder is not allowed");
349 final User user = dao.getEntityById(User.class, userId);
350 if (!folder.hasDeletePermission(user)) {
351 logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
352 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
354 removeSubfolderFiles(folder);
355 parent.removeSubfolder(folder);
357 touchParentFolders(parent, user, new Date());
361 * Traverses the folder and deletes all actual files (file system)
362 * regardless of permissions
366 private void removeSubfolderFiles(Folder folder) {
367 //remove files for all subfolders
368 for (Folder subfolder:folder.getSubfolders())
369 removeSubfolderFiles(subfolder);
370 //remove this folder's file bodies (actual files)
371 for (FileHeader file:folder.getFiles()) {
372 for (FileBody body:file.getBodies())
373 deleteActualFile(body.getStoredFilePath());
374 indexFile(file.getId(), true);
379 @SuppressWarnings("unchecked")
380 public List<Folder> getSubfolders(Long userId, Long folderId)
381 throws ObjectNotFoundException, InsufficientPermissionsException {
383 throw new ObjectNotFoundException("No user specified");
384 if (folderId == null)
385 throw new ObjectNotFoundException("No folder specified");
386 User user = dao.getEntityById(User.class, userId);
387 Folder folder = dao.getEntityById(Folder.class, folderId);
388 if (!folder.hasReadPermission(user))
389 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
390 List<Folder> result = new ArrayList<Folder>();
391 if (folder.hasReadPermission(user))
392 for (Folder f : folder.getSubfolders())
393 if (f.hasReadPermission(user) && !f.isDeleted())
399 public Folder updateFolder(Long userId, Long folderId, String folderName,
401 Set<Permission> permissions)
402 throws InsufficientPermissionsException, ObjectNotFoundException,
403 DuplicateNameException {
407 throw new ObjectNotFoundException("No user specified");
408 if (folderId == null)
409 throw new ObjectNotFoundException("No folder specified");
411 Folder folder = dao.getEntityById(Folder.class, folderId);
412 User user = dao.getEntityById(User.class, userId);
413 if (folderName != null && !folder.hasWritePermission(user))
414 throw new InsufficientPermissionsException("You don't have the necessary permissions");
415 if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
416 throw new InsufficientPermissionsException("You don't have the necessary permissions");
417 // Check permissions for making file public.
418 if (readForAll != null && !user.equals(folder.getOwner()))
419 throw new InsufficientPermissionsException("Only the owner can make a folder public or not public");
421 Folder parent = folder.getParent();
422 if (folderName != null) {
424 if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
425 throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
427 // Do the actual modification.
428 folder.setName(folderName);
430 if (permissions != null)
431 setFolderPermissions(user, folder, permissions);
432 if (readForAll != null)
433 setFolderReadForAll(user, folder, readForAll);
434 folder.getAuditInfo().setModificationDate(new Date());
435 folder.getAuditInfo().setModifiedBy(user);
437 touchParentFolders(folder, user, new Date());
438 // Re-index the folder contents if it was modified.
439 if ((permissions != null && !permissions.isEmpty()) || readForAll != null) {
446 private void indexFolder(Folder folder) {
447 for (FileHeader fh : folder.getFiles())
448 indexFile(fh.getId(), false);
449 for (Folder f : folder.getSubfolders())
454 public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
457 throw new ObjectNotFoundException("No user specified");
458 if (StringUtils.isEmpty(name))
459 throw new ObjectNotFoundException("New group name is empty");
460 if (name.indexOf('/')>=0)
461 throw new IllegalArgumentException("Character '/' is not allowed in group name");
462 if (dao.existsGroup(userId, name))
463 throw new DuplicateNameException("A group with the name '" + name + "' already exists");
465 // TODO: Check permissions
467 final User owner = dao.getEntityById(User.class, userId);
469 // Do the actual work.
470 owner.createGroup(name);
474 public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
477 throw new ObjectNotFoundException("No user specified");
479 throw new ObjectNotFoundException("No group specified");
481 // Do the actual work.
482 final User owner = dao.getEntityById(User.class, userId);
483 final Group group = dao.getEntityById(Group.class, groupId);
484 final Date now = new Date();
485 // Only delete the group if actually owned by the user.
486 if (group.getOwner().equals(owner)) {
487 List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
488 for (Folder f : folders){
489 f.getPermissions().removeAll(group.getPermissions());
490 for(FileHeader file : f.getFiles()){
491 file.getPermissions().removeAll(group.getPermissions());
494 List<FileHeader> files = dao.getFilesPermittedForGroup(userId, groupId);
495 for(FileHeader h : files){
496 h.getPermissions().removeAll(group.getPermissions());
498 owner.removeSpecifiedGroup(group);
501 else throw new InsufficientPermissionsException("You are not the owner of this group");
505 public FileHeader createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
506 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
507 InsufficientPermissionsException, QuotaExceededException {
510 file = uploadFile(stream, userId);
511 } catch ( IOException ioe) {
512 // Supply a more accurate problem description.
513 throw new GSSIOException("Problem creating file",ioe);
515 return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
519 * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
522 public void indexFile(Long fileId, boolean delete) {
523 Connection qConn = null;
524 Session session = null;
525 MessageProducer sender = null;
527 Context jndiCtx = new InitialContext();
528 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
529 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
530 qConn = factory.createConnection();
531 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
532 sender = session.createProducer(queue);
534 MapMessage map = session.createMapMessage();
535 map.setObject("id", fileId);
536 map.setBoolean("delete", delete);
539 catch (NamingException e) {
540 logger.error("Index was not updated: ", e);
542 catch (JMSException e) {
543 logger.error("Index was not updated: ", e);
554 catch (JMSException e) {
563 * A helper method that generates a unique file path for a stored file. The
564 * files are stored using random hash names that are distributed evenly in
565 * a 2-level tree of subdirectories named after the first two hex characters
566 * in the name. For example, file ab1234cd5769f will be stored in the path
567 * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
568 * if they don't already exist.
570 * @return a unique new file path
572 private String generateRepositoryFilePath() {
573 String filename = Long.toHexString(random.nextLong());
574 String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
575 File root = new File(fileRepositoryPath);
578 File firstFolder = new File(root + File.separator + filename.substring(0, 1));
579 if (!firstFolder.exists())
581 File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
582 if (!secondFolder.exists())
583 secondFolder.mkdir();
584 return secondFolder + File.separator + filename;
588 public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
591 throw new ObjectNotFoundException("No user specified");
593 throw new ObjectNotFoundException("No file specified");
595 // Do the actual work.
596 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
597 final Folder parent = file.getFolder();
599 throw new ObjectNotFoundException("The specified file has no parent folder");
600 final User user = dao.getEntityById(User.class, userId);
601 if (!file.hasDeletePermission(user))
602 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
603 for (final FileBody body : file.getBodies())
604 deleteActualFile(body.getStoredFilePath());
606 touchParentFolders(parent, user, new Date());
607 indexFile(fileId, true);
611 public void deleteActualFile(String path) {
614 File file = new File(path);
616 logger.error("Could not delete file " + path);
620 public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
622 throw new ObjectNotFoundException("No user specified");
623 if (fileHeaderId == null)
624 throw new ObjectNotFoundException("No file specified");
625 if (StringUtils.isEmpty(tag))
626 throw new ObjectNotFoundException("Tag is empty");
628 final User user = dao.getEntityById(User.class, userId);
629 final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
630 final Folder parent = fh.getFolder();
632 throw new ObjectNotFoundException("The specified file has no parent folder");
633 user.addTag(fh, tag);
634 touchParentFolders(parent, user, new Date());
638 public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
639 return dao.getUserTags(userId);
643 public void updateFile(Long userId, Long fileId, String name,
644 String tagSet, Date modificationDate, Boolean versioned,
645 Boolean readForAll, Set<Permission> permissions)
646 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
648 throw new ObjectNotFoundException("No user specified");
650 throw new ObjectNotFoundException("No file specified");
651 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
652 final Folder parent = file.getFolder();
654 throw new ObjectNotFoundException("The specified file has no parent folder");
656 User user = dao.getEntityById(User.class, userId);
657 // Check permissions for modifying the file metadata.
658 if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
659 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
660 // Check permissions for making file public.
661 if (readForAll != null && !user.equals(file.getOwner()))
662 throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
663 // Check permissions for modifying the ACL.
664 if(permissions != null && !permissions.isEmpty() && !file.hasModifyACLPermission(user))
665 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update the permissions on file " + file.getName() + "(" + file.getId() + ")");
668 // Do plain check for file already exists.
669 // Extreme concurrency case should be caught by constraint violation later.
670 if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
674 if (modificationDate != null)
675 file.getAuditInfo().setModificationDate(modificationDate);
677 file.getAuditInfo().setModificationDate(new Date());
678 file.getAuditInfo().setModifiedBy(user);
680 List<FileTag> tags = file.getFileTags();
681 if (tagSet != null) {
682 Iterator<FileTag> i = tags.iterator();
683 while (i.hasNext()) {
684 FileTag tag = i.next();
691 StringTokenizer st = new StringTokenizer(tagSet, ",");
692 while (st.hasMoreTokens())
693 new FileTag(user, file, st.nextToken().trim());
695 if (versioned != null && !file.isVersioned() == versioned) {
696 if (file.isVersioned())
697 removeOldVersions(userId, fileId);
698 file.setVersioned(versioned);
700 if (readForAll != null && user.equals(file.getOwner()))
701 file.setReadForAll(readForAll);
702 if (permissions != null && !permissions.isEmpty())
703 setFilePermissions(file, permissions);
706 * Force constraint violation to manifest itself here.
707 * This should cover extreme concurrency cases that the simple check
708 * above hasn't caught.
713 catch (EJBTransactionRolledbackException e) {
714 Throwable cause = e.getCause();
715 if (cause instanceof PersistenceException && cause.getCause() instanceof ConstraintViolationException)
716 throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
720 touchParentFolders(parent, user, new Date());
722 // Re-index the file if it was modified.
723 if (name != null || tagSet != null || (permissions != null && !permissions.isEmpty()) || readForAll != null)
724 indexFile(fileId, false);
728 public InputStream getFileContents(Long userId, Long fileId)
729 throws ObjectNotFoundException, InsufficientPermissionsException {
731 throw new ObjectNotFoundException("No user specified");
733 throw new ObjectNotFoundException("No file specified");
735 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
736 User user = dao.getEntityById(User.class, userId);
737 if (!header.hasReadPermission(user)) {
738 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
739 throw new InsufficientPermissionsException("You don't have the necessary permissions");
742 File f = new File(header.getCurrentBody().getStoredFilePath());
744 return new FileInputStream(f);
745 } catch (FileNotFoundException e) {
746 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
747 throw new ObjectNotFoundException("The file contents could not be located");
752 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
755 public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
757 throw new ObjectNotFoundException("No user specified");
759 throw new ObjectNotFoundException("No file specified");
761 throw new ObjectNotFoundException("No file specified");
763 final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
764 final FileBody body = dao.getEntityById(FileBody.class, bodyId);
765 final User user = dao.getEntityById(User.class, userId);
766 if (!header.hasReadPermission(user)) {
767 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
768 throw new InsufficientPermissionsException("You don't have the necessary permissions");
771 File f = new File(body.getStoredFilePath());
773 return new FileInputStream(f);
774 } catch (FileNotFoundException e) {
775 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
776 throw new ObjectNotFoundException("The file contents could not be located");
781 public FileHeader getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
783 throw new ObjectNotFoundException("No user specified");
785 throw new ObjectNotFoundException("No file specified");
786 final User user = dao.getEntityById(User.class, userId);
787 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
788 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
789 throw new InsufficientPermissionsException("You don't have the necessary permissions");
794 public FileBody getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
796 throw new ObjectNotFoundException("No user specified");
798 throw new ObjectNotFoundException("No file specified");
799 User user = dao.getEntityById(User.class, userId);
800 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
801 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
802 throw new InsufficientPermissionsException("You don't have the necessary permissions");
803 FileBody body = dao.getEntityById(FileBody.class, bodyId);
808 public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
809 throws ObjectNotFoundException {
811 throw new ObjectNotFoundException("No user specified");
812 if (StringUtils.isEmpty(path))
813 throw new ObjectNotFoundException("No path specified");
815 User owner = dao.getEntityById(User.class, ownerId);
816 List<String> pathElements = new ArrayList<String>();
817 StringTokenizer st = new StringTokenizer(path, "/");
818 while (st.hasMoreTokens())
819 pathElements.add(st.nextToken());
820 if (pathElements.size() < 1)
821 return getRootFolder(owner.getId());
822 // Store the last element, since it requires special handling.
823 String lastElement = pathElements.remove(pathElements.size() - 1);
825 Folder cursor = null;
826 Long rootFolderId = getRootFolderId(owner.getId());
827 // Traverse and verify the specified folder path.
828 for (String pathElement : pathElements) {
829 cursor = getFolder(cursor==null ? rootFolderId : cursor.getId(), pathElement);
830 if (cursor.isDeleted())
831 throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
834 // Use the lastElement to retrieve the actual resource.
835 Object resource = null;
837 FileHeader file = getFile(cursor==null ? rootFolderId : cursor.getId(), lastElement);
838 if (ignoreDeleted && file.isDeleted())
839 throw new ObjectNotFoundException("Resource not found");
841 } catch (ObjectNotFoundException e) {
842 // Perhaps the requested resource is not a file, so
843 // check for folders as well.
844 Folder folder = getFolder(cursor==null ? rootFolderId : cursor.getId(), lastElement);
845 if (ignoreDeleted && folder.isDeleted())
846 throw new ObjectNotFoundException("Resource not found");
853 * Retrieve a file for the specified user that has the specified name and
854 * its parent folder has id equal to folderId.
856 * @param folderId the ID of the parent folder
857 * @param name the name of the requested file
858 * @return the file found
859 * @throws ObjectNotFoundException if the specified folder or file was not
860 * found, with the exception message mentioning the precise
863 private FileHeader getFile(Long folderId, String name) throws ObjectNotFoundException {
864 if (folderId == null)
865 throw new ObjectNotFoundException("No parent folder specified");
866 if (StringUtils.isEmpty(name))
867 throw new ObjectNotFoundException("No file specified");
869 FileHeader file = dao.getFile(folderId, name);
874 * Retrieve a folder for the specified user that has the specified name and
875 * its parent folder has id equal to parentId.
877 * @param parentId the ID of the parent folder
878 * @param name the name of the requested folder
879 * @return the folder found
880 * @throws ObjectNotFoundException if the specified folder or parent was not
881 * found, with the exception message mentioning the precise
884 private Folder getFolder(Long parentId, String name) throws ObjectNotFoundException {
885 if (parentId == null)
886 throw new ObjectNotFoundException("No parent folder specified");
887 if (StringUtils.isEmpty(name))
888 throw new ObjectNotFoundException("No folder specified");
890 Folder folder = dao.getFolder(parentId, name);
894 private FileHeader updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
897 file = uploadFile(resourceInputStream, userId);
898 } catch ( IOException ioe) {
899 // Supply a more accurate problem description.
900 throw new GSSIOException("Problem creating file",ioe);
902 return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
906 public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
908 throw new ObjectNotFoundException("No user specified");
910 throw new ObjectNotFoundException("No file specified");
911 if (StringUtils.isEmpty(dest))
912 throw new ObjectNotFoundException("No destination specified");
914 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
915 if (!(destination instanceof Folder))
916 throw new ObjectNotFoundException("Destination parent folder not found");
917 Folder parent = (Folder) destination;
918 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
922 public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
924 throw new ObjectNotFoundException("No user specified");
926 throw new ObjectNotFoundException("No owner specified");
928 throw new ObjectNotFoundException("No file specified");
929 if (StringUtils.isEmpty(dest))
930 throw new ObjectNotFoundException("No destination specified");
932 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
933 if (!(destination instanceof Folder))
934 throw new ObjectNotFoundException("Destination parent folder not found");
935 Folder parent = (Folder) destination;
936 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
940 public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
942 throw new ObjectNotFoundException("No user specified");
944 throw new ObjectNotFoundException("No file specified");
946 throw new ObjectNotFoundException("No destination specified");
947 if (StringUtils.isEmpty(destName))
948 throw new ObjectNotFoundException("No destination file name specified");
950 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
951 Folder destination = dao.getEntityById(Folder.class, destId);
952 User user = dao.getEntityById(User.class, userId);
953 if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
954 throw new InsufficientPermissionsException("You don't have the necessary permissions");
955 boolean versioned = file.isVersioned();
956 int versionsNumber = file.getBodies().size();
957 FileBody oldestBody = file.getBodies().get(0);
958 assert oldestBody != null;
959 File contents = new File(oldestBody.getStoredFilePath());
961 createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
962 FileHeader copiedFile = dao.getFile(destination.getId(), destName);
963 copiedFile.setVersioned(versioned);
965 if (versionsNumber > 1)
966 for (int i = 1; i < versionsNumber; i++) {
967 FileBody body = file.getBodies().get(i);
969 contents = new File(body.getStoredFilePath());
970 updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
972 List<FileTag> tags = file.getFileTags();
973 for (FileTag tag : tags)
974 createTag(userId, copiedFile.getId(), tag.getTag());
976 } catch (FileNotFoundException e) {
977 throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
983 public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
985 throw new ObjectNotFoundException("No user specified");
986 if (folderId == null)
987 throw new ObjectNotFoundException("No folder specified");
988 if (StringUtils.isEmpty(dest))
989 throw new ObjectNotFoundException("No destination specified");
991 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
992 if (!(destination instanceof Folder))
993 throw new ObjectNotFoundException("Destination folder not found");
994 Folder parent = (Folder) destination;
995 copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
999 public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1001 throw new ObjectNotFoundException("No user specified");
1002 if (folderId == null)
1003 throw new ObjectNotFoundException("No folder specified");
1005 throw new ObjectNotFoundException("No destination specified");
1006 if (StringUtils.isEmpty(destName))
1007 throw new ObjectNotFoundException("No destination folder name specified");
1008 Folder folder = dao.getEntityById(Folder.class, folderId);
1009 Folder destination = dao.getEntityById(Folder.class, destId);
1010 User user = dao.getEntityById(User.class, userId);
1011 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1012 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1013 createFolder(user.getId(), destination.getId(), destName);
1017 public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1019 throw new ObjectNotFoundException("No user specified");
1020 if (ownerId == null)
1021 throw new ObjectNotFoundException("No owner specified");
1022 if (folderId == null)
1023 throw new ObjectNotFoundException("No folder specified");
1024 if (StringUtils.isEmpty(dest))
1025 throw new ObjectNotFoundException("No destination specified");
1027 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1028 if (!(destination instanceof Folder))
1029 throw new ObjectNotFoundException("Destination folder not found");
1030 Folder parent = (Folder) destination;
1031 copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1035 public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1037 throw new ObjectNotFoundException("No user specified");
1038 if (folderId == null)
1039 throw new ObjectNotFoundException("No folder specified");
1041 throw new ObjectNotFoundException("No destination specified");
1042 if (StringUtils.isEmpty(destName))
1043 throw new ObjectNotFoundException("No destination folder name specified");
1045 Folder folder = dao.getEntityById(Folder.class, folderId);
1046 Folder destination = dao.getEntityById(Folder.class, destId);
1047 final User user = dao.getEntityById(User.class, userId);
1048 // XXX: quick fix need to copy only visible items to user (Source
1050 if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1052 if(folder.isDeleted())//do not copy trashed folder and contents
1054 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1055 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1056 createFolder(user.getId(), destination.getId(), destName);
1057 Folder createdFolder = dao.getFolder(destination.getId(), destName);
1058 List<FileHeader> files = folder.getFiles();
1060 for (FileHeader file : files)
1061 if(!file.isDeleted())
1062 copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1063 List<Folder> subFolders = folder.getSubfolders();
1064 if (subFolders != null)
1065 for (Folder sub : subFolders)
1066 if(!sub.getId().equals(createdFolder.getId()))
1067 copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1072 * For a provided path, remove the last element and return the rest, that is
1073 * the path of the parent folder.
1075 * @param path the specified path
1076 * @return the path of the parent folder
1077 * @throws ObjectNotFoundException if the provided string contains no path
1080 private String getParentPath(String path) throws ObjectNotFoundException {
1081 int lastDelimiter = path.lastIndexOf('/');
1082 if (lastDelimiter == 0)
1084 if (lastDelimiter == -1)
1086 throw new ObjectNotFoundException("There is no parent in the path: " + path);
1087 else if (lastDelimiter < path.length() - 1)
1088 // Return the part before the delimiter.
1089 return path.substring(0, lastDelimiter);
1091 // Remove the trailing delimiter and then recurse.
1092 String strippedTrail = path.substring(0, lastDelimiter);
1093 return getParentPath(strippedTrail);
1098 * Get the last element in a path that denotes the file or folder name.
1100 * @param path the provided path
1101 * @return the last element in the path
1103 private String getLastElement(String path) {
1104 int lastDelimiter = path.lastIndexOf('/');
1105 if (lastDelimiter == -1)
1108 else if (lastDelimiter < path.length() - 1)
1109 // Return the part after the delimiter.
1110 return path.substring(lastDelimiter + 1);
1112 // Remove the trailing delimiter and then recurse.
1113 String strippedTrail = path.substring(0, lastDelimiter);
1114 return getLastElement(strippedTrail);
1119 public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1121 throw new ObjectNotFoundException("No user specified");
1123 throw new ObjectNotFoundException("No file specified");
1125 // Do the actual work.
1126 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1127 Folder parent = file.getFolder();
1129 throw new ObjectNotFoundException("The specified file has no parent folder");
1130 User user = dao.getEntityById(User.class, userId);
1131 trashFile(user, file);
1132 touchParentFolders(parent, user, new Date());
1135 private void trashFile(User user, FileHeader file) throws InsufficientPermissionsException {
1136 if (!file.hasDeletePermission(user))
1137 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1139 file.setDeleted(true);
1143 public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1145 throw new ObjectNotFoundException("No user specified");
1146 if (ownerId == null)
1147 throw new ObjectNotFoundException("No owner specified");
1149 throw new ObjectNotFoundException("No file specified");
1150 if (StringUtils.isEmpty(dest))
1151 throw new ObjectNotFoundException("No destination specified");
1153 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1154 if (!(destination instanceof Folder))
1155 throw new ObjectNotFoundException("Destination parent folder not found");
1156 Folder parent = (Folder) destination;
1157 moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1161 public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1163 throw new ObjectNotFoundException("No user specified");
1165 throw new ObjectNotFoundException("No file specified");
1167 throw new ObjectNotFoundException("No destination specified");
1168 if (StringUtils.isEmpty(destName))
1169 throw new ObjectNotFoundException("No destination file name specified");
1171 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1172 Folder source = file.getFolder();
1173 Folder destination = dao.getEntityById(Folder.class, destId);
1175 User owner = dao.getEntityById(User.class, userId);
1176 if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1177 throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1179 // if the destination folder belongs to another user:
1180 if (!file.getOwner().equals(destination.getOwner())) {
1181 // (a) check if the destination quota allows the move
1182 if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1183 throw new QuotaExceededException("Not enough free space available");
1184 User newOwner = destination.getOwner();
1185 // (b) if quota OK, change the owner of the file
1186 file.setOwner(newOwner);
1187 // if the file has no permission for the new owner, add it
1188 Permission ownerPermission = null;
1189 for (final Permission p : file.getPermissions())
1190 if (p.getUser() != null)
1191 if (p.getUser().equals(newOwner)) {
1192 ownerPermission = p;
1195 if (ownerPermission == null) {
1196 ownerPermission = new Permission();
1197 ownerPermission.setUser(newOwner);
1198 file.addPermission(ownerPermission);
1200 ownerPermission.setRead(true);
1201 ownerPermission.setWrite(true);
1202 ownerPermission.setModifyACL(true);
1204 // move the file to the destination folder
1205 file.setFolder(destination);
1206 touchParentFolders(source, owner, new Date());
1207 touchParentFolders(destination, owner, new Date());
1211 public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1213 throw new ObjectNotFoundException("No user specified");
1214 if (ownerId == null)
1215 throw new ObjectNotFoundException("No owner specified");
1216 if (folderId == null)
1217 throw new ObjectNotFoundException("No folder specified");
1218 if (StringUtils.isEmpty(dest))
1219 throw new ObjectNotFoundException("No destination specified");
1221 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1222 if (!(destination instanceof Folder))
1223 throw new ObjectNotFoundException("Destination parent folder not found");
1224 Folder parent = (Folder) destination;
1225 moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1229 public void moveFolder(Long userId, Long folderId, Long destId, String destName)
1230 throws ObjectNotFoundException, InsufficientPermissionsException,
1231 QuotaExceededException {
1232 Folder source = dao.getEntityById(Folder.class, folderId);
1233 Folder destination = dao.getEntityById(Folder.class, destId);
1234 User user = dao.getEntityById(User.class, userId);
1235 User sourceOwner = source.getOwner();
1236 User destinationOwner = destination.getOwner();
1237 // Do not move trashed folders and contents.
1238 if (source.isDeleted())
1240 // Check permissions.
1241 if (!destination.hasWritePermission(user)
1242 || !source.hasReadPermission(user)
1243 || !source.hasWritePermission(user))
1244 throw new InsufficientPermissionsException("You don't have the " +
1245 "necessary permissions");
1246 // Use the same timestamp for all subsequent modifications to make
1247 // changes appear simultaneous.
1248 Date now = new Date();
1249 // If source and destination are not in the same user's namespace,
1250 // change owners and check quota.
1251 if (!sourceOwner.equals(destinationOwner)) {
1252 changeOwner(source, destinationOwner, user, now);
1253 if (getQuotaLeft(destinationOwner.getId()) < 0)
1254 throw new QuotaExceededException("Not enough free space " +
1255 "available in destination folder");
1257 // Perform the move.
1258 Folder oldParent = source.getParent();
1259 oldParent.removeSubfolder(source);
1260 destination.addSubfolder(source);
1261 // Mark the former parent and destination trees upwards as modified.
1262 touchParentFolders(oldParent, user, now);
1263 touchParentFolders(source, user, now);
1267 * Recursively change the owner of the specified folder and all of its
1268 * contents to the specified owner. Also mark them all as modified with the
1269 * specified modifier and modificationDate.
1271 private void changeOwner(Folder folder, User owner, User modifier, Date modificationDate) {
1272 for (FileHeader file: folder.getFiles()) {
1273 file.setOwner(owner);
1274 file.getAuditInfo().setModificationDate(modificationDate);
1275 file.getAuditInfo().setModifiedBy(modifier);
1277 for (Folder sub: folder.getSubfolders())
1278 changeOwner(sub, owner, modifier, modificationDate);
1279 folder.setOwner(owner);
1280 folder.getAuditInfo().setModificationDate(modificationDate);
1281 folder.getAuditInfo().setModifiedBy(modifier);
1285 public List<FileHeader> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1288 throw new ObjectNotFoundException("No user specified");
1290 // Do the actual work.
1291 final List<FileHeader> files = dao.getDeletedFiles(userId);
1296 public void removeFileFromTrash(Long userId, Long fileId)
1297 throws ObjectNotFoundException, InsufficientPermissionsException {
1299 throw new ObjectNotFoundException("No user specified");
1301 throw new ObjectNotFoundException("No file specified");
1303 // Do the actual work.
1304 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1305 Folder parent = file.getFolder();
1307 throw new ObjectNotFoundException("The specified file has no parent folder");
1308 User user = dao.getEntityById(User.class, userId);
1309 untrashFile(user, file);
1310 touchParentFolders(parent, user, new Date());
1313 private void untrashFile(User user, FileHeader file) throws InsufficientPermissionsException {
1314 if (!file.hasDeletePermission(user))
1315 throw new InsufficientPermissionsException("User " + user.getUsername() +
1316 " cannot restore file " + file.getName());
1318 file.setDeleted(false);
1322 public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1324 throw new ObjectNotFoundException("No user specified");
1325 if (folderId == null)
1326 throw new ObjectNotFoundException("No folder specified");
1327 Folder folder = dao.getEntityById(Folder.class, folderId);
1328 User user = dao.getEntityById(User.class, userId);
1329 trashFolder(user, folder);
1330 touchParentFolders(folder, user, new Date());
1333 private void trashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException {
1334 if (!folder.hasDeletePermission(user))
1335 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1336 folder.setDeleted(true);
1337 for (FileHeader file : folder.getFiles())
1338 trashFile(user, file);
1339 for (Folder subFolder : folder.getSubfolders())
1340 trashFolder(user, subFolder);
1344 public void removeFolderFromTrash(Long userId, Long folderId)
1345 throws ObjectNotFoundException, InsufficientPermissionsException {
1347 throw new ObjectNotFoundException("No user specified");
1348 if (folderId == null)
1349 throw new ObjectNotFoundException("No folder specified");
1350 Folder folder = dao.getEntityById(Folder.class, folderId);
1351 User user = dao.getEntityById(User.class, userId);
1352 untrashFolder(user, folder);
1353 touchParentFolders(folder, user, new Date());
1356 private void untrashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException {
1357 if (!folder.hasDeletePermission(user))
1358 throw new InsufficientPermissionsException("User " + user.getUsername() +
1359 " cannot restore folder " + folder.getName());
1360 folder.setDeleted(false);
1361 for (FileHeader file : folder.getFiles())
1362 untrashFile(user, file);
1363 for (Folder subFolder : folder.getSubfolders())
1364 untrashFolder(user, subFolder);
1368 public List<Folder> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1369 List<Folder> folders = dao.getDeletedRootFolders(userId);
1374 public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1375 List<Folder> deletedRootFolders = getDeletedRootFolders(userId);
1376 for (Folder folder : deletedRootFolders)
1377 deleteFolder(userId, folder.getId());
1378 List<FileHeader> deletedFiles = getDeletedFiles(userId);
1379 for (FileHeader file : deletedFiles)
1380 deleteFile(userId, file.getId());
1384 public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1385 List<Folder> deletedRootFolders = getDeletedRootFolders(userId);
1386 for (Folder folder : deletedRootFolders)
1387 removeFolderFromTrash(userId, folder.getId());
1388 List<FileHeader> deletedFiles = getDeletedFiles(userId);
1389 for (FileHeader file : deletedFiles)
1390 removeFileFromTrash(userId, file.getId());
1394 public User createUser(String username, String name, String mail,
1395 String idp, String idpid) throws ObjectNotFoundException {
1396 if (username == null)
1397 throw new ObjectNotFoundException("No username specified");
1399 throw new ObjectNotFoundException("No name specified");
1401 User user = new User();
1402 user.setUsername(username);
1404 user.setEmail(mail);
1405 user.setIdentityProvider(idp);
1406 user.setIdentityProviderId(idpid);
1407 Date now = new Date();
1408 AuditInfo auditInfo = new AuditInfo();
1409 auditInfo.setCreationDate(now);
1410 auditInfo.setModificationDate(now);
1411 user.setAuditInfo(auditInfo);
1412 user.setActive(true);
1413 user.generateAuthToken();
1414 user.generateWebDAVPassword();
1415 user.setUserClass(getDefaultUserClass());
1417 // Make sure we get an ID in the user object.
1419 // Create the root folder for the user.
1420 createFolder(user.getName(), null, user);
1425 * Get the default user class, which is the one with the lowest quota.
1427 private UserClass getDefaultUserClass() {
1428 return getUserClasses().get(0);
1432 public List<UserClass> getUserClasses() {
1433 List<UserClass> classes = dao.getUserClasses();
1434 // Create a default user class for first-time use. Afterwards, the
1435 // admin should modify or add to the userclass table.
1436 if (classes.size() == 0) {
1437 UserClass defaultClass = new UserClass();
1438 defaultClass.setName("default");
1439 Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L));
1440 defaultClass.setQuota(defaultQuota);
1441 dao.create(defaultClass);
1442 classes.add(defaultClass);
1448 public User findUserByEmail(String email) {
1449 return dao.findUserByEmail(email);
1453 public void updateUser(User user) {
1458 public User findUser(String username) {
1459 if (username == null)
1461 return dao.findUser(username);
1465 public User updateUserToken(Long userId) throws ObjectNotFoundException {
1467 throw new ObjectNotFoundException("No user specified");
1468 User user = dao.getEntityById(User.class, userId);
1469 user.generateAuthToken();
1474 public Set<Permission> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1476 throw new ObjectNotFoundException("No user specified");
1477 if (folderId == null)
1478 throw new ObjectNotFoundException("No folder specified");
1479 User user = dao.getEntityById(User.class, userId);
1480 Folder folder = dao.getEntityById(Folder.class, folderId);
1481 if(!folder.hasReadPermission(user))
1482 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1483 Set<Permission> perms = folder.getPermissions();
1484 Set<Permission> result = new LinkedHashSet<Permission>();
1485 for (Permission perm : perms)
1486 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1488 for (Permission perm : perms)
1489 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1497 * Set the provided permissions as the new permissions of the specified
1502 * @param permissions
1503 * @throws ObjectNotFoundException
1504 * @throws InsufficientPermissionsException
1506 private void setFolderPermissions(User user, Folder folder, Set<Permission> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1507 if (permissions != null && !permissions.isEmpty()) {
1508 User owner = folder.getOwner();
1509 Permission ownerPerm = null;
1510 for (Permission perm : permissions)
1511 if (perm.getUser() != null && perm.getUser().getId().equals(owner.getId())) {
1515 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1516 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1517 // Delete previous entries
1518 for (Permission perm: folder.getPermissions())
1520 folder.getPermissions().clear();
1521 for (Permission p : permissions) {
1522 // Skip 'empty' permission entries.
1523 if (!p.getRead() && !p.getWrite() && !p.getModifyACL()) continue;
1524 folder.addPermission(getPermission(p));
1527 for (FileHeader file : folder.getFiles()) {
1528 setFilePermissions(file, permissions);
1529 Date now = new Date();
1530 file.getAuditInfo().setModificationDate(now);
1531 file.getAuditInfo().setModifiedBy(user);
1533 for (Folder sub : folder.getSubfolders())
1534 setFolderPermissions(user, sub, permissions);
1538 private Permission getPermission(Permission perm) throws ObjectNotFoundException {
1539 Permission res = new Permission();
1540 if (perm.getGroup() != null)
1541 res.setGroup(dao.getEntityById(Group.class, perm.getGroup().getId()));
1542 else if (perm.getUser() != null)
1543 if (perm.getUser().getId() == null)
1544 res.setUser(dao.getUser(perm.getUser().getUsername()));
1546 res.setUser(dao.getEntityById(User.class, perm.getUser().getId()));
1547 res.setRead(perm.hasRead());
1548 res.setWrite(perm.hasWrite());
1549 res.setModifyACL(perm.hasModifyACL());
1554 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1557 public List<User> getUsersByUserNameLike(String username) {
1558 List<User> users = dao.getUsersByUserNameLike(username);
1564 public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1566 throw new ObjectNotFoundException("No user specified");
1567 if (groupId == null)
1568 throw new ObjectNotFoundException("No group specified");
1569 if (userToAddId == null)
1570 throw new ObjectNotFoundException("No user to add specified");
1571 User user = dao.getEntityById(User.class, userId);
1572 Group group = dao.getEntityById(Group.class, groupId);
1573 if (!group.getOwner().equals(user))
1574 throw new InsufficientPermissionsException();
1575 User userToAdd = dao.getEntityById(User.class, userToAddId);
1576 if (group.contains(userToAdd))
1577 throw new DuplicateNameException("User already exists in group");
1578 group.getMembers().add(userToAdd);
1584 public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1586 throw new ObjectNotFoundException("No user specified");
1587 User user = dao.getEntityById(User.class, userId);
1588 user.invalidateAuthToken();
1593 public List<Folder> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1595 throw new ObjectNotFoundException("No user specified");
1596 List<Folder> folders = dao.getSharedRootFolders(userId);
1597 List<Folder> result = new ArrayList<Folder>();
1598 for (Folder f : folders) {
1600 lf.setSubfolders(getSharedSubfolders(userId, f.getId()));
1607 public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1609 throw new ObjectNotFoundException("No user specified");
1610 if (groupId == null)
1611 throw new ObjectNotFoundException("No group specified");
1612 if (memberId == null)
1613 throw new ObjectNotFoundException("No member specified");
1614 User owner = dao.getEntityById(User.class, userId);
1615 Group group = dao.getEntityById(Group.class, groupId);
1616 User member = dao.getEntityById(User.class, memberId);
1617 if (!group.getOwner().equals(owner))
1618 throw new InsufficientPermissionsException("User is not the owner of the group");
1619 group.removeMemberFromGroup(member);
1625 public List<User> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1626 List<User> users = dao.getUsersSharingFoldersForUser(userId);
1627 List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1628 List<User> result = new ArrayList<User>();
1629 for (User u : users)
1631 for(User fu : usersFiles)
1632 if(!users.contains(fu))
1638 public Set<Permission> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1640 throw new ObjectNotFoundException("No user specified");
1642 throw new ObjectNotFoundException("No folder specified");
1643 User user = dao.getEntityById(User.class, userId);
1644 FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1645 if(!folder.hasReadPermission(user))
1646 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1647 Set<Permission> perms = folder.getPermissions();
1648 Set<Permission> result = new LinkedHashSet<Permission>();
1649 for (Permission perm : perms)
1650 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1652 for (Permission perm : perms)
1653 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1660 * Set the provided permissions as the new permissions of the specified
1661 * file. This method sets the modification date/user attributes to the
1662 * current values as a side effect.
1665 * @param permissions
1666 * @throws ObjectNotFoundException
1667 * @throws InsufficientPermissionsException
1669 private void setFilePermissions(FileHeader file,
1670 Set<Permission> permissions)
1671 throws ObjectNotFoundException, InsufficientPermissionsException {
1672 if (permissions != null && !permissions.isEmpty()) {
1673 Permission ownerPerm = null;
1674 for (Permission perm : permissions)
1675 if (perm.getUser() != null && perm.getUser().getId().equals(file.getOwner().getId())) {
1679 if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1680 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1681 // Delete previous entries.
1682 for (Permission perm: file.getPermissions())
1684 file.getPermissions().clear();
1685 for (Permission perm : permissions) {
1686 // Skip 'empty' permission entries.
1687 if (!perm.getRead() && !perm.getWrite() && !perm.getModifyACL()) continue;
1688 file.addPermission(getPermission(perm));
1695 public List<FileHeader> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1697 throw new ObjectNotFoundException("No user specified");
1698 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1703 public List<FileHeader> getSharedFiles(Long userId) throws ObjectNotFoundException {
1705 throw new ObjectNotFoundException("No user specified");
1706 List<FileHeader> files = dao.getSharedFiles(userId);
1711 public List<Folder> getSharedFolders(Long userId) throws ObjectNotFoundException {
1713 throw new ObjectNotFoundException("No user specified");
1714 List<Folder> folders = dao.getSharedFolders(userId);
1719 public List<FileHeader> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1720 if (ownerId == null)
1721 throw new ObjectNotFoundException("No owner specified");
1722 if (callingUserId == null)
1723 throw new ObjectNotFoundException("No calling user specified");
1724 List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1729 public List<Folder> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1730 if (ownerId == null)
1731 throw new ObjectNotFoundException("No owner specified");
1732 if (callingUserId == null)
1733 throw new ObjectNotFoundException("No calling user specified");
1734 List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1735 List<Folder> result = new ArrayList<Folder>();
1736 for (Folder f : folders) {
1738 lf.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1746 public List<Folder> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1748 throw new ObjectNotFoundException("No user specified");
1749 if (folderId == null)
1750 throw new ObjectNotFoundException("No folder specified");
1751 User user = dao.getEntityById(User.class, userId);
1752 Folder folder = dao.getEntityById(Folder.class, folderId);
1753 List<Folder> result = new ArrayList<Folder>();
1754 if (folder.isShared(user) || folder.isReadForAll())
1755 for (Folder f : folder.getSubfolders())
1756 if ((f.isShared(user) || f.isReadForAll()) && !f.isDeleted())
1762 public List<Folder> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1764 throw new ObjectNotFoundException("No user specified");
1765 if (callingUserId == null)
1766 throw new ObjectNotFoundException("No user specified");
1767 if (folderId == null)
1768 throw new ObjectNotFoundException("No folder specified");
1769 User user = dao.getEntityById(User.class, callingUserId);
1770 Folder folder = dao.getEntityById(Folder.class, folderId);
1771 List<Folder> result = new ArrayList<Folder>();
1772 if (folder.isSharedForOtherUser(user))
1773 for (Folder f : folder.getSubfolders())
1774 if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1776 lf.setSubfolders(getSharedSubfolders(userId, callingUserId, lf.getId()));
1784 public List<FileHeader> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1785 long startTime = System.currentTimeMillis();
1787 throw new ObjectNotFoundException("No user specified");
1788 User user = getUser(userId);
1790 throw new ObjectNotFoundException("No query specified");
1791 List<FileHeader> files = search(user.getId(), query);
1793 long stopTime = System.currentTimeMillis();
1794 logger.info("Total time: " + (stopTime - startTime));
1799 * Performs the actuals search on the solr server and returns the results
1803 * @return a List of FileHeader objects
1805 private List<FileHeader> search(Long userId, String query) {
1806 final int maxRows = 100;
1807 List<FileHeader> result = new ArrayList<FileHeader>();
1809 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
1810 List<Group> groups = dao.getGroupsContainingUser(userId);
1811 String constructedQuery = escapeCharacters(normalizeSearchQuery(query)) + " AND (public: true OR ureaders: " + userId;
1812 if (!groups.isEmpty()) {
1813 constructedQuery += " OR (";
1814 for (int i=0; i<groups.size(); i++) {
1815 Group g = groups.get(i);
1816 constructedQuery += "greaders :" + g.getId();
1817 if (i < groups.size() - 1)
1818 constructedQuery += " OR ";
1820 constructedQuery += ")";
1822 constructedQuery += ")";
1823 SolrQuery solrQuery = new SolrQuery(constructedQuery);
1824 solrQuery.setRows(maxRows);
1825 long startTime = System.currentTimeMillis();
1826 QueryResponse response = solr.query(solrQuery);
1827 SolrDocumentList results = response.getResults();
1828 if (results.getNumFound() > maxRows) {
1829 solrQuery.setRows(Integer.valueOf((int) results.getNumFound()));
1830 response = solr.query(solrQuery);
1831 results = response.getResults();
1833 long stopTime = System.currentTimeMillis();
1834 logger.info("Search time:" + (stopTime - startTime));
1835 User user = getUser(userId);
1836 startTime = System.currentTimeMillis();
1837 for (SolrDocument d : results) {
1838 Long id = Long.valueOf((String) d.getFieldValue("id"));
1840 FileHeader f = dao.getEntityById(FileHeader.class, id);
1842 } catch (ObjectNotFoundException e) {
1843 logger.warn("Search result id " + id + " cannot be found", e);
1846 stopTime = System.currentTimeMillis();
1847 logger.info("File loads: " + (stopTime - startTime));
1848 } catch (MalformedURLException e) {
1850 throw new EJBException(e);
1851 } catch (SolrServerException e) {
1853 throw new EJBException(e);
1854 } catch (ObjectNotFoundException e) {
1856 throw new EJBException(e);
1862 public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1863 for(Long l : fileIds){
1864 FileHeader file = dao.getEntityById(FileHeader.class, l);
1865 copyFile(userId, l, destId, file.getName());
1872 public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1873 for(Long l : fileIds){
1874 FileHeader file = dao.getEntityById(FileHeader.class, l);
1875 moveFile(userId, l, destId, file.getName());
1881 public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1883 throw new ObjectNotFoundException("No user specified");
1884 User user = dao.getEntityById(User.class, userId);
1885 Nonce nonce = Nonce.createNonce(user.getId());
1891 public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1893 throw new ObjectNotFoundException("No user specified");
1895 throw new ObjectNotFoundException("No nonce specified");
1896 return dao.getNonce(nonce, userId);
1900 public void removeNonce(Long id) throws ObjectNotFoundException {
1902 throw new ObjectNotFoundException("No nonce specified");
1903 Nonce nonce = dao.getEntityById(Nonce.class, id);
1908 public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1910 throw new ObjectNotFoundException("No user specified");
1911 User user = dao.getEntityById(User.class, userId);
1912 user.setNonce(nonce);
1913 user.setNonceExpiryDate(nonceExpiryDate);
1917 public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1919 throw new ObjectNotFoundException("No user specified");
1920 StatsDTO stats = new StatsDTO();
1921 stats.setFileCount(dao.getFileCount(userId));
1922 Long fileSize = dao.getFileSize(userId);
1923 stats.setFileSize(fileSize);
1924 Long quota = getQuota(userId);
1925 Long quotaLeft = quota - fileSize;
1926 stats.setQuotaLeftSize(quotaLeft);
1931 public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1933 throw new ObjectNotFoundException("No user specified");
1935 throw new ObjectNotFoundException("No file specified");
1936 User user = dao.getEntityById(User.class, userId);
1937 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1938 if(!header.hasWritePermission(user))
1939 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1940 FileBody body = dao.getFileVersion(fileId, version);
1941 final File fileContents = new File(body.getStoredFilePath());
1944 updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
1945 } catch (FileNotFoundException e) {
1946 throw new GSSIOException(e);
1952 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
1955 public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1957 throw new ObjectNotFoundException("No user specified");
1959 throw new ObjectNotFoundException("No file specified");
1960 User user = dao.getEntityById(User.class, userId);
1961 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1962 if(!header.hasWritePermission(user))
1963 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1964 Iterator<FileBody> it = header.getBodies().iterator();
1965 while(it.hasNext()){
1966 FileBody body = it.next();
1967 if(!body.equals(header.getCurrentBody())){
1968 deleteActualFile(body.getStoredFilePath());
1973 header.getCurrentBody().setVersion(1);
1975 Folder parent = header.getFolder();
1976 touchParentFolders(parent, user, new Date());
1980 * Gets the quota left for specified user ID.
1982 private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
1983 Long fileSize = dao.getFileSize(userId);
1984 Long quota = getQuota(userId);
1985 return quota - fileSize;
1989 * Gets the quota for specified user ID.
1991 private Long getQuota(Long userId) throws ObjectNotFoundException{
1992 UserClass uc = getUser(userId).getUserClass();
1994 uc = getDefaultUserClass();
1995 return uc.getQuota();
1999 @TransactionAttribute(TransactionAttributeType.NEVER)
2000 public String rebuildSolrIndex() {
2002 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2003 solr.deleteByQuery("*:*");
2005 logger.info("Deleted everything in solr");
2007 List<Long> fileIds = dao.getAllFileIds();
2008 logger.info("Total of " + fileIds.size() + " will be indexed");
2010 for (Long id : fileIds) {
2011 postFileToSolr(solr, id);
2015 logger.info("Sent commit to solr at file " + i);
2020 logger.info("Finished indexing of " + i + " files");
2021 return "Finished indexing of " + i + " files";
2022 } catch (IOException e) {
2023 throw new EJBException(e);
2024 } catch (SolrServerException e) {
2025 throw new EJBException(e);
2030 @TransactionAttribute(TransactionAttributeType.NEVER)
2031 public String refreshSolrIndex() {
2033 CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2035 List<Long> fileIds = dao.getAllFileIds();
2036 logger.info("Total of " + fileIds.size() + " will be indexed");
2038 for (Long id : fileIds) {
2039 postFileToSolr(solr, id);
2044 logger.info("Sent commit to solr at file " + i);
2048 logger.info("Finished indexing of " + i + " files");
2049 return "Finished indexing of " + i + " files";
2050 } catch (IOException e) {
2051 throw new EJBException(e);
2052 } catch (SolrServerException e) {
2053 throw new EJBException(e);
2058 public FileHeader createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2059 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2060 InsufficientPermissionsException, QuotaExceededException {
2063 throw new ObjectNotFoundException("No user specified");
2064 if (folderId == null)
2065 throw new ObjectNotFoundException("No folder specified");
2066 String contentType = mimeType;
2067 if (StringUtils.isEmpty(mimeType))
2068 contentType = DEFAULT_MIME_TYPE;
2069 if (StringUtils.isEmpty(name))
2070 throw new ObjectNotFoundException("No file name specified");
2071 if (dao.existsFolderOrFile(folderId, name))
2072 throw new DuplicateNameException("A folder or file with the name '" + name +
2073 "' already exists at this level");
2075 // Do the actual work.
2076 Folder parent = null;
2078 parent = dao.getEntityById(Folder.class, folderId);
2079 } catch (final ObjectNotFoundException onfe) {
2080 // Supply a more accurate problem description.
2081 throw new ObjectNotFoundException("Parent folder not found");
2083 final User owner = dao.getEntityById(User.class, userId);
2084 if (!parent.hasWritePermission(owner))
2085 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2086 final FileHeader file = new FileHeader();
2088 parent.addFile(file);
2089 // set file owner to folder owner
2090 file.setOwner(parent.getOwner());
2091 //set file's readForAll value according to parent folder readForAll value
2092 file.setReadForAll(parent.isReadForAll());
2094 final Date now = new Date();
2095 final AuditInfo auditInfo = new AuditInfo();
2096 auditInfo.setCreatedBy(owner);
2097 auditInfo.setCreationDate(now);
2098 auditInfo.setModifiedBy(owner);
2099 auditInfo.setModificationDate(now);
2100 file.setAuditInfo(auditInfo);
2101 // TODO set the proper versioning flag on creation
2102 file.setVersioned(false);
2104 for (final Permission p : parent.getPermissions()) {
2105 final Permission permission = new Permission();
2106 permission.setGroup(p.getGroup());
2107 permission.setUser(p.getUser());
2108 permission.setRead(p.getRead());
2109 permission.setWrite(p.getWrite());
2110 permission.setModifyACL(p.getModifyACL());
2111 file.addPermission(permission);
2114 // Create the file body.
2116 createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2117 } catch (FileNotFoundException e) {
2118 throw new GSSIOException(e);
2120 touchParentFolders(parent, owner, new Date());
2122 indexFile(file.getId(), false);
2128 public FileHeader updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2130 throw new ObjectNotFoundException("No user specified");
2132 throw new ObjectNotFoundException("No file specified");
2133 String contentType = mimeType;
2135 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2137 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2138 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2139 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2140 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2141 contentType = identifyMimeType(file.getName());
2143 final User owner = dao.getEntityById(User.class, userId);
2144 if (!file.hasWritePermission(owner))
2145 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2146 final Date now = new Date();
2147 final AuditInfo auditInfo = new AuditInfo();
2148 auditInfo.setCreatedBy(owner);
2149 auditInfo.setCreationDate(now);
2150 auditInfo.setModifiedBy(owner);
2151 auditInfo.setModificationDate(now);
2153 createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2154 } catch (FileNotFoundException e) {
2155 throw new GSSIOException(e);
2157 Folder parent = file.getFolder();
2158 touchParentFolders(parent, owner, new Date());
2160 indexFile(fileId, false);
2165 * Helper method for identifying mime type by examining the filename extension
2168 * @return the mime type
2170 private String identifyMimeType(String filename) {
2171 if (filename.indexOf('.') != -1) {
2172 String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2173 if (".doc".equals(extension))
2174 return "application/msword";
2175 else if (".xls".equals(extension))
2176 return "application/vnd.ms-excel";
2177 else if (".ppt".equals(extension))
2178 return "application/vnd.ms-powerpoint";
2179 else if (".pdf".equals(extension))
2180 return "application/pdf";
2181 else if (".gif".equals(extension))
2183 else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2184 return "image/jpeg";
2185 else if (".tiff".equals(extension) || ".tif".equals(extension))
2186 return "image/tiff";
2187 else if (".png".equals(extension))
2189 else if (".bmp".equals(extension))
2192 // when all else fails assign the default mime type
2193 return DEFAULT_MIME_TYPE;
2197 * Helper method to create a new file body and attach it as the current body
2198 * of the provided file header.
2200 * @param name the original file name
2201 * @param mimeType the content type
2202 * @param fileSize the uploaded file size
2203 * @param filePath the uploaded file full path
2204 * @param header the file header that will be associated with the new body
2205 * @param auditInfo the audit info
2206 * @throws FileNotFoundException
2207 * @throws QuotaExceededException
2208 * @throws ObjectNotFoundException if the owner was not found
2210 private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2211 FileHeader header, AuditInfo auditInfo)
2212 throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2214 long currentTotalSize = 0;
2215 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2216 currentTotalSize = header.getTotalSize();
2217 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2218 if(quotaLeft < fileSize-currentTotalSize) {
2219 // quota exceeded -> delete the file
2220 deleteActualFile(filePath);
2221 throw new QuotaExceededException("Not enough free space available");
2224 FileBody body = new FileBody();
2226 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2227 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2228 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2229 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2230 body.setMimeType(identifyMimeType(name));
2232 body.setMimeType(mimeType);
2233 body.setAuditInfo(auditInfo);
2234 body.setFileSize(fileSize);
2235 body.setOriginalFilename(name);
2236 body.setStoredFilePath(filePath);
2237 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2238 if(!header.isVersioned() && header.getCurrentBody() != null){
2239 header.setCurrentBody(null);
2240 if (header.getBodies() != null) {
2241 Iterator<FileBody> it = header.getBodies().iterator();
2242 while(it.hasNext()){
2243 FileBody bo = it.next();
2244 deleteActualFile(bo.getStoredFilePath());
2252 header.addBody(body);
2253 header.setAuditInfo(auditInfo);
2260 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2261 public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2263 throw new ObjectNotFoundException("No user specified");
2264 User owner = dao.getEntityById(User.class, userId);
2266 throw new ObjectNotFoundException("No user specified");
2267 long start = 0, end = 0;
2268 if (logger.isDebugEnabled())
2269 start = System.currentTimeMillis();
2270 File result = new File(generateRepositoryFilePath());
2272 final FileOutputStream output = new FileOutputStream(result);
2273 final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2276 while (-1 != (n = stream.read(buffer)))
2277 output.write(buffer, 0, n);
2280 } catch (IOException e) {
2281 if (!result.delete())
2282 logger.warn("Could not delete " + result.getPath());
2285 if (logger.isDebugEnabled()) {
2286 end = System.currentTimeMillis();
2287 logger.debug("Time to upload: " + (end - start) + " (msec)");
2294 public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2297 throw new ObjectNotFoundException("No user specified");
2298 User user = dao.getEntityById(User.class, userId);
2299 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2301 status = new FileUploadStatus();
2302 status.setOwner(user);
2303 status.setFilename(filename);
2304 status.setBytesUploaded(bytesTransfered);
2305 status.setFileSize(fileSize);
2309 status.setBytesUploaded(bytesTransfered);
2310 status.setFileSize(fileSize);
2317 public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2319 throw new ObjectNotFoundException("No user specified");
2320 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2326 public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2327 return dao.getFileUploadStatus(userId, fileName);
2331 public FileBody getFileVersion(Long userId, Long fileId, int version)
2332 throws ObjectNotFoundException, InsufficientPermissionsException {
2334 throw new ObjectNotFoundException("No user specified");
2336 throw new ObjectNotFoundException("No file specified");
2338 throw new ObjectNotFoundException("No valid version specified");
2339 User user = dao.getEntityById(User.class, userId);
2340 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2341 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2342 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2343 FileBody body = dao.getFileVersion(fileId, version);
2348 public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2350 throw new ObjectNotFoundException("No user specified");
2351 User user = dao.getEntityById(User.class, userId);
2352 user.setAcceptedPolicy(isAccepted);
2357 public void updateAccounting(User user, Date date, long bandwidthDiff) {
2358 dao.updateAccounting(user, date, bandwidthDiff);
2362 public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2364 throw new ObjectNotFoundException("No user specified");
2365 if (folderId == null)
2366 throw new ObjectNotFoundException("No folder specified");
2367 User user = dao.getEntityById(User.class, userId);
2368 Folder folder = dao.getEntityById(Folder.class, folderId);
2369 // Check permissions
2370 if (!folder.hasReadPermission(user))
2376 public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2378 throw new ObjectNotFoundException("No user specified");
2379 User user = dao.getEntityById(User.class, userId);
2380 user.generateWebDAVPassword();
2381 return user.getWebDAVPassword();
2385 public Invitation findInvite(String code) {
2388 return dao.findInvite(code);
2392 public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2393 LDAPConnection lc = new LDAPConnection();
2394 LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2395 attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2396 attributeSet.add(new LDAPAttribute("uid", username));
2397 attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2398 attributeSet.add(new LDAPAttribute("sn", lastname));
2399 attributeSet.add(new LDAPAttribute("givenName", firstname));
2400 attributeSet.add(new LDAPAttribute("mail", email));
2401 attributeSet.add(new LDAPAttribute("userPassword", password));
2402 String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2403 LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2405 lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2406 lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2407 getConfiguration().getString("bindPassword").getBytes("UTF8"));
2409 logger.info("Successfully added LDAP account: " + dn);
2411 } catch(LDAPException e) {
2412 throw new RuntimeException(e);
2413 } catch(UnsupportedEncodingException e) {
2414 throw new RuntimeException(e);
2420 public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2421 User user = findUser(username);
2423 throw new ObjectNotFoundException("The user was not found");
2424 Invitation invite = findInvite(code);
2425 if (invite.getUser() != null)
2426 throw new InvitationUsedException("This code has already been used");
2427 invite.setUser(user);
2428 UserClass couponClass = getCouponUserClass();
2429 user.setUserClass(couponClass);
2434 public UserClass getCouponUserClass() {
2435 return dao.findCouponUserClass();
2439 * Set the provided readForAll as the new readforAll value of the specified
2440 * folder and sub-folders.
2445 * @throws ObjectNotFoundException
2448 private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){
2449 if (readForAll != null && user.equals(folder.getOwner())){
2450 folder.setReadForAll(readForAll);
2452 for (FileHeader file : folder.getFiles())
2453 file.setReadForAll(readForAll);
2455 //only update subfolders when readforall is true. otherwise all sub-folders stay untouched
2456 for (Folder sub : folder.getSubfolders())
2457 setFolderReadForAll(user, sub, readForAll);
2464 * Update the userLogin with the values from the supplied object.
2467 public void addUserLogin(UserLogin userLogin) {
2468 dao.update(userLogin);
2473 * Retrieves the current session user login and the user's last login
2476 * @return a list of last two user logins
2477 * @throws ObjectNotFoundException
2480 public List<UserLogin> getLastUserLogins(Long userId) throws ObjectNotFoundException{
2481 List<UserLogin> userLoginResults = new ArrayList<UserLogin>();
2482 userLoginResults = dao.getLoginsForUser(userId);
2483 if(userLoginResults.size() == 0)
2484 throw new ObjectNotFoundException("No userlogin found for the user");
2485 //if the user logins for the first time lastLoginDate = currentLoginDate
2486 if(userLoginResults.size()==1)
2487 userLoginResults.add(userLoginResults.get(0));
2488 return userLoginResults;
2493 public void postFileToSolr(CommonsHttpSolrServer solr, Long id) {
2495 FileHeader file = dao.getFileForIndexing(id);
2496 FileBody body = file.getCurrentBody();
2497 String mime = body.getMimeType();
2498 boolean multipart = true;
2499 if (!mime.equals("application/pdf")
2500 && !mime.equals("text/plain")
2501 && !mime.equals("text/html")
2502 && !mime.endsWith("msword")
2503 && !mime.endsWith("ms-excel")
2504 && !mime.endsWith("powerpoint")
2505 || (body.getFileSize() > getConfiguration().getLong("solrDocumentUploadLimitInKB") * 1024))
2509 sendMetaDataOnly(solr, file);
2511 ContentStreamUpdateRequest solrRequest = new ContentStreamUpdateRequest(getConfiguration().getString("solr.rich.update.path"));
2512 solrRequest.setParam("literal.id", file.getId().toString());
2513 solrRequest.setParam("literal.name", file.getName());
2514 for (FileTag t : file.getFileTags()) {
2515 solrRequest.getParams().add("literal.tag", t.getTag());
2517 for (Permission p : file.getPermissions()) {
2519 if (p.getUser() != null)
2520 solrRequest.getParams().add("literal.ureaders", p.getUser().getId().toString());
2521 else if (p.getGroup() != null)
2522 solrRequest.getParams().add("literal.greaders", p.getGroup().getId().toString());
2525 solrRequest.setParam("literal.owner", file.getOwner().getId().toString());
2526 solrRequest.setParam("literal.public", String.valueOf(file.isReadForAll()));
2527 File fsFile = new File(body.getStoredFilePath());
2528 solrRequest.addFile(fsFile);
2530 solr.request(solrRequest);
2532 catch (SolrException e) {
2533 logger.warn("File " + id + " failed with SolrException: " + e.getLocalizedMessage() + ". Retrying without the file");
2534 //Let 's try without the file
2535 sendMetaDataOnly(solr, file);
2537 catch (NullPointerException e) {
2538 logger.warn("File " + id + " failed with NullPointerException: " + e.getLocalizedMessage() + ". Retrying without the file");
2539 //Let 's try without the file
2540 sendMetaDataOnly(solr, file);
2542 catch (SolrServerException e) {
2543 logger.warn("File " + id + " failed with SolrServerException: " + e.getLocalizedMessage() + ". Retrying without the file");
2544 //Let 's try without the file
2545 sendMetaDataOnly(solr, file);
2548 } catch (MalformedURLException e) {
2549 throw new EJBException(e);
2550 } catch (ObjectNotFoundException e) {
2551 logger.error("Indexing of file id " + id + " failed.", e);
2552 } catch (SolrServerException e) {
2553 throw new EJBException(e);
2554 } catch (IOException e) {
2555 throw new EJBException(e);
2559 private void sendMetaDataOnly(CommonsHttpSolrServer solr, FileHeader file) throws SolrServerException, IOException {
2560 SolrInputDocument solrDoc = new SolrInputDocument();
2561 solrDoc.addField("id", file.getId().toString());
2562 solrDoc.addField("name", file.getName());
2563 for (FileTag t : file.getFileTags()) {
2564 solrDoc.addField("tag", t.getTag());
2566 for (Permission p : file.getPermissions()) {
2568 if (p.getUser() != null)
2569 solrDoc.addField("ureaders", p.getUser().getId());
2570 else if (p.getGroup() != null)
2571 solrDoc.addField("greaders", p.getGroup().getId());
2574 solrDoc.addField("owner", file.getOwner().getId());
2575 solrDoc.addField("public", file.isReadForAll());
2579 private String tokenizeFilename(String filename){
2580 StringBuffer result = new StringBuffer();
2581 StringTokenizer tokenizer = new StringTokenizer(filename,"._");
2582 while(tokenizer.hasMoreTokens()){
2583 result.append(tokenizer.nextToken());
2586 result.append(filename);
2587 return result.toString();
2590 private String normalizeSearchQuery(String query) {
2591 if (query.contains("*"))
2592 return query.toLowerCase().replace('ά', 'α').replace('έ', 'ε').replace('ί', 'ι').replace('ή', 'η').replace('ύ', 'υ')
2593 .replace('ό', 'ο').replace('ς', 'σ').replace('ώ', 'ω').replace('ϊ', 'ι').replace('ϋ', 'υ');
2598 private String escapeCharacters(String text) {
2599 return text.replaceAll(":", "\\\\:");
2602 /*** NEW METHODS IN ORDER TO AVOID LAZY loading exception in json render
2605 public Folder expandFolder(Folder folder) throws ObjectNotFoundException{
2606 Folder result = dao.getEntityById(Folder.class, folder.getId());
2607 result.getSubfolders().size();
2608 result.getFiles().size();
2609 result.getPermissions().size();
2614 public FileHeader expandFile(FileHeader folder) throws ObjectNotFoundException{
2615 FileHeader result = dao.getEntityById(FileHeader.class, folder.getId());
2617 result.getPermissions().size();
2618 result.getFileTags().size();
2623 public Group expandGroup(Group folder) throws ObjectNotFoundException{
2624 Group result = dao.getEntityById(Group.class, folder.getId());
2625 result.getMembers().size();
2630 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
2633 public User getUserByUserName(String username) {
2634 User result = dao.getUserByUserName(username);
2638 /*WEBDAV CREATE EMPTY FILE*/
2640 public FileHeader createEmptyFile(Long userId, Long folderId, String name)
2641 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2642 InsufficientPermissionsException, QuotaExceededException {
2645 throw new ObjectNotFoundException("No user specified");
2646 if (folderId == null)
2647 throw new ObjectNotFoundException("No folder specified");
2648 String contentType = DEFAULT_MIME_TYPE;
2649 if (StringUtils.isEmpty(name))
2650 throw new ObjectNotFoundException("No file name specified");
2651 if (dao.existsFolderOrFile(folderId, name))
2652 throw new DuplicateNameException("A folder or file with the name '" + name +
2653 "' already exists at this level");
2655 // Do the actual work.
2656 Folder parent = null;
2658 parent = dao.getEntityById(Folder.class, folderId);
2659 } catch (final ObjectNotFoundException onfe) {
2660 // Supply a more accurate problem description.
2661 throw new ObjectNotFoundException("Parent folder not found");
2663 final User owner = dao.getEntityById(User.class, userId);
2664 if (!parent.hasWritePermission(owner))
2665 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2666 final FileHeader file = new FileHeader();
2668 parent.addFile(file);
2669 // set file owner to folder owner
2670 file.setOwner(parent.getOwner());
2671 //set file's readForAll value according to parent folder readForAll value
2672 file.setReadForAll(parent.isReadForAll());
2674 final Date now = new Date();
2675 final AuditInfo auditInfo = new AuditInfo();
2676 auditInfo.setCreatedBy(owner);
2677 auditInfo.setCreationDate(now);
2678 auditInfo.setModifiedBy(owner);
2679 auditInfo.setModificationDate(now);
2680 file.setAuditInfo(auditInfo);
2681 // TODO set the proper versioning flag on creation
2682 file.setVersioned(false);
2684 for (final Permission p : parent.getPermissions()) {
2685 final Permission permission = new Permission();
2686 permission.setGroup(p.getGroup());
2687 permission.setUser(p.getUser());
2688 permission.setRead(p.getRead());
2689 permission.setWrite(p.getWrite());
2690 permission.setModifyACL(p.getModifyACL());
2691 file.addPermission(permission);
2693 // Create the file body.
2695 createEmptyFileBody(name, contentType, 0, file, auditInfo);
2696 } catch (FileNotFoundException e) {
2697 throw new GSSIOException(e);
2699 touchParentFolders(parent, owner, new Date());
2704 private void createEmptyFileBody(String name, String mimeType, long fileSize,
2705 FileHeader header, AuditInfo auditInfo)
2706 throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2708 long currentTotalSize = 0;
2709 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2710 currentTotalSize = header.getTotalSize();
2711 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2714 FileBody body = new FileBody();
2716 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2717 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2718 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2719 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2720 body.setMimeType(identifyMimeType(name));
2722 body.setMimeType(mimeType);
2723 body.setAuditInfo(auditInfo);
2724 body.setFileSize(fileSize);
2725 body.setOriginalFilename(name);
2726 body.setStoredFilePath(generateRepositoryFilePath());
2727 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2728 if(!header.isVersioned() && header.getCurrentBody() != null){
2729 header.setCurrentBody(null);
2730 if (header.getBodies() != null) {
2731 Iterator<FileBody> it = header.getBodies().iterator();
2732 while(it.hasNext()){
2733 FileBody bo = it.next();
2734 deleteActualFile(bo.getStoredFilePath());
2742 header.addBody(body);
2743 header.setAuditInfo(auditInfo);
2747 /*** WEBDAV LOCK **/
2749 public FileLock getLockById(String id) {
2750 return dao.getLockById(id);
2754 public FileLock getLockByToken(String tokenId) {
2755 return dao.getLockByToken(tokenId);
2759 public void removeLock(FileLock lock) {
2760 dao.removeLock(lock);
2764 public FileLock saveOrUpdateLock(FileLock lock) {
2765 return dao.saveOrUpdateLock(lock);
2769 public WebDavNonce getWebDavNonce(String tokenId) {
2770 return dao.getWebDavNonce(tokenId);
2774 public void removeWebDavNonce(WebDavNonce nonce) {
2775 dao.removeWebDavNonce(nonce);
2779 public WebDavNonce saveOrUpdateWebDavNonce(WebDavNonce nonce) {
2780 return dao.saveOrUpdateWebDavNonce(nonce);
2784 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
2787 public UserDTO getUserByUserName(String username) {
2788 User result = dao.getUserByUserName(username);
2789 return result.getDTO();