2 * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
4 * This file is part of GSS.
6 * GSS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GSS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GSS. If not, see <http://www.gnu.org/licenses/>.
19 package gr.ebs.gss.server.ejb;
21 import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
22 import gr.ebs.gss.client.exceptions.DuplicateNameException;
23 import gr.ebs.gss.client.exceptions.GSSIOException;
24 import gr.ebs.gss.client.exceptions.InsufficientPermissionsException;
25 import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
26 import gr.ebs.gss.client.exceptions.QuotaExceededException;
27 import gr.ebs.gss.server.domain.AuditInfo;
28 import gr.ebs.gss.server.domain.FileBody;
29 import gr.ebs.gss.server.domain.FileHeader;
30 import gr.ebs.gss.server.domain.FileTag;
31 import gr.ebs.gss.server.domain.FileUploadStatus;
32 import gr.ebs.gss.server.domain.Folder;
33 import gr.ebs.gss.server.domain.Group;
34 import gr.ebs.gss.server.domain.Nonce;
35 import gr.ebs.gss.server.domain.Permission;
36 import gr.ebs.gss.server.domain.User;
37 import gr.ebs.gss.server.domain.dto.FileBodyDTO;
38 import gr.ebs.gss.server.domain.dto.FileHeaderDTO;
39 import gr.ebs.gss.server.domain.dto.FolderDTO;
40 import gr.ebs.gss.server.domain.dto.GroupDTO;
41 import gr.ebs.gss.server.domain.dto.PermissionDTO;
42 import gr.ebs.gss.server.domain.dto.StatsDTO;
43 import gr.ebs.gss.server.domain.dto.UserDTO;
46 import java.io.FileInputStream;
47 import java.io.FileNotFoundException;
48 import java.io.FileOutputStream;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.io.StringWriter;
52 import java.io.UnsupportedEncodingException;
53 import java.util.ArrayList;
54 import java.util.Date;
55 import java.util.Iterator;
56 import java.util.LinkedHashSet;
57 import java.util.LinkedList;
58 import java.util.List;
59 import java.util.Locale;
60 import java.util.Random;
62 import java.util.StringTokenizer;
65 import javax.ejb.EJBException;
66 import javax.ejb.Stateless;
67 import javax.ejb.TransactionAttribute;
68 import javax.ejb.TransactionAttributeType;
69 import javax.jms.Connection;
70 import javax.jms.ConnectionFactory;
71 import javax.jms.JMSException;
72 import javax.jms.MapMessage;
73 import javax.jms.MessageProducer;
74 import javax.jms.Queue;
75 import javax.jms.QueueConnectionFactory;
76 import javax.jms.Session;
77 import javax.jws.WebMethod;
78 import javax.naming.Context;
79 import javax.naming.InitialContext;
80 import javax.naming.NamingException;
81 import javax.xml.parsers.DocumentBuilder;
82 import javax.xml.parsers.DocumentBuilderFactory;
83 import javax.xml.parsers.ParserConfigurationException;
84 import javax.xml.transform.OutputKeys;
85 import javax.xml.transform.Transformer;
86 import javax.xml.transform.TransformerConfigurationException;
87 import javax.xml.transform.TransformerException;
88 import javax.xml.transform.TransformerFactory;
89 import javax.xml.transform.dom.DOMSource;
90 import javax.xml.transform.stream.StreamResult;
92 import org.apache.commons.httpclient.HttpClient;
93 import org.apache.commons.httpclient.HttpException;
94 import org.apache.commons.httpclient.NameValuePair;
95 import org.apache.commons.httpclient.methods.GetMethod;
96 import org.apache.commons.httpclient.methods.PostMethod;
97 import org.apache.commons.httpclient.methods.StringRequestEntity;
98 import org.apache.commons.lang.StringUtils;
99 import org.apache.commons.logging.Log;
100 import org.apache.commons.logging.LogFactory;
101 import org.w3c.dom.DOMException;
102 import org.w3c.dom.Document;
103 import org.w3c.dom.Node;
104 import org.w3c.dom.NodeList;
105 import org.xml.sax.SAXException;
108 * The concrete implementation of the ExternalAPI interface.
113 public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
115 * The default MIME type for files without an explicit one.
117 private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
120 * The size of the buffer that is used to temporarily store chunks of
121 * uploaded files, while storing them to the file repository.
123 private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
128 private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
131 * Injected reference to the GSSDAO data access facade.
138 * A cached random number generator for creating unique filenames.
140 private static Random random = new Random();
142 private void touchParentFolders(Folder folder, User modifiedBy, Date modificationDate) {
145 AuditInfo ai = f.getAuditInfo();
146 ai.setModifiedBy(modifiedBy);
147 ai.setModificationDate(modificationDate);
154 public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
156 throw new ObjectNotFoundException("No user specified");
157 Folder folder = dao.getRootFolder(userId);
158 return folder.getDTO();
164 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolder(java.lang.Long)
166 public FolderDTO getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
168 throw new ObjectNotFoundException("No user specified");
169 if (folderId == null)
170 throw new ObjectNotFoundException("No folder specified");
171 final User user = dao.getEntityById(User.class, userId);
172 final Folder folder = dao.getEntityById(Folder.class, folderId);
174 if (!folder.hasReadPermission(user))
175 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
176 return folder.getDTO();
180 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUser(java.lang.Long)
182 public User getUser(Long userId) throws ObjectNotFoundException {
184 throw new ObjectNotFoundException("No user specified");
185 return dao.getEntityById(User.class, userId);
189 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserDTO(java.lang.Long)
191 public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
192 return getUser(userId).getDTO();
198 * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroup(java.lang.Long)
200 public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
202 throw new ObjectNotFoundException("No group specified");
203 final Group group = dao.getEntityById(Group.class, groupId);
204 return group.getDTO();
208 public GroupDTO getGroup(Long userId, String name) throws ObjectNotFoundException {
210 throw new ObjectNotFoundException("No user specified");
212 throw new ObjectNotFoundException("No group specified");
213 User user = dao.getEntityById(User.class, userId);
214 List<Group> groups = user.getGroupsSpecified();
215 for (Group group: groups)
216 if (group.getName().equals(name))
217 return group.getDTO();
218 throw new ObjectNotFoundException("Group " + name + " not found");
224 * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroups(java.lang.Long)
226 public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
228 throw new ObjectNotFoundException("No user specified");
229 final List<Group> groups = dao.getGroups(userId);
230 final List<GroupDTO> result = new ArrayList<GroupDTO>();
231 for (final Group g : groups)
232 result.add(g.getDTO());
237 public List<FileHeaderDTO> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
238 throws ObjectNotFoundException, InsufficientPermissionsException {
241 throw new ObjectNotFoundException("No user specified");
242 if (folderId == null)
243 throw new ObjectNotFoundException("No folder specified");
244 User user = dao.getEntityById(User.class, userId);
245 Folder folder = dao.getEntityById(Folder.class, folderId);
246 if (!folder.hasReadPermission(user))
247 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
248 // Do the actual work.
249 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
250 List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
251 for (FileHeader f : files)
252 result.add(f.getDTO());
259 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsers(java.lang.Long,
262 public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
265 throw new ObjectNotFoundException("No user specified");
267 throw new ObjectNotFoundException("No group specified");
269 // Do the actual work.
270 final List<User> users = dao.getUsers(groupId);
271 final List<UserDTO> result = new ArrayList<UserDTO>();
272 for (final User u : users)
273 result.add(u.getDTO());
278 public FolderDTO createFolder(Long userId, Long parentId, String name)
279 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
282 throw new ObjectNotFoundException("No user specified");
283 if (StringUtils.isEmpty(name))
284 throw new ObjectNotFoundException("New folder name is empty");
285 if (parentId == null)
286 throw new ObjectNotFoundException("No parent specified");
287 if (dao.existsFolderOrFile(parentId, name))
288 throw new DuplicateNameException("A folder or file with the name '" +
289 name + "' already exists at this level");
291 User creator = dao.getEntityById(User.class, userId);
293 Folder parent = null;
295 parent = dao.getEntityById(Folder.class, parentId);
296 } catch (ObjectNotFoundException onfe) {
297 // Supply a more accurate problem description.
298 throw new ObjectNotFoundException("Parent folder not found");
300 if (!parent.hasWritePermission(creator))
301 throw new InsufficientPermissionsException("You don't have the permissions" +
302 " to write to this folder");
304 // Do the actual work.
305 return createFolder(name, parent, creator);
309 * Create a new folder with the provided name, parent and owner.
314 * @return the new folder
316 private FolderDTO createFolder(String name, Folder parent, User creator) {
317 Folder folder = new Folder();
318 folder.setName(name);
319 if (parent != null) {
320 parent.addSubfolder(folder);
321 folder.setOwner(parent.getOwner());
323 folder.setOwner(creator);
325 Date now = new Date();
326 AuditInfo auditInfo = new AuditInfo();
327 auditInfo.setCreatedBy(creator);
328 auditInfo.setCreationDate(now);
329 auditInfo.setModifiedBy(creator);
330 auditInfo.setModificationDate(now);
331 folder.setAuditInfo(auditInfo);
332 touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
335 for (Permission p : parent.getPermissions()) {
336 Permission permission = new Permission();
337 permission.setGroup(p.getGroup());
338 permission.setUser(p.getUser());
339 permission.setRead(p.getRead());
340 permission.setWrite(p.getWrite());
341 permission.setModifyACL(p.getModifyACL());
342 folder.addPermission(permission);
345 Permission permission = new Permission();
346 permission.setUser(creator);
347 permission.setRead(true);
348 permission.setWrite(true);
349 permission.setModifyACL(true);
350 folder.addPermission(permission);
353 return folder.getDTO();
357 * Deletes the given folder and all its subfolders and files
358 * Only the permissions for top folder are checked
360 * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFolder(java.lang.Long,
363 public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
366 throw new ObjectNotFoundException("No user specified");
367 if (folderId == null)
368 throw new ObjectNotFoundException("No folder specified");
370 // Do the actual work.
371 final Folder folder = dao.getEntityById(Folder.class, folderId);
372 final Folder parent = folder.getParent();
374 throw new ObjectNotFoundException("Deleting the root folder is not allowed");
375 final User user = dao.getEntityById(User.class, userId);
376 if (!folder.hasDeletePermission(user)) {
377 logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
378 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
380 removeSubfolderFiles(folder);
381 parent.removeSubfolder(folder);
383 touchParentFolders(parent, user, new Date());
387 * Traverses the folder and deletes all actual files (file system)
388 * regardless of permissions
392 private void removeSubfolderFiles(Folder folder) {
393 //remove files for all subfolders
394 for (Folder subfolder:folder.getSubfolders())
395 removeSubfolderFiles(subfolder);
396 //remove this folder's file bodies (actual files)
397 for (FileHeader file:folder.getFiles()) {
398 for (FileBody body:file.getBodies())
399 deleteActualFile(body.getStoredFilePath());
400 indexFile(file.getId(), true);
404 @SuppressWarnings("unchecked")
405 public List<FolderDTO> getSubfolders(Long userId, Long folderId)
406 throws ObjectNotFoundException, InsufficientPermissionsException {
408 throw new ObjectNotFoundException("No user specified");
409 if (folderId == null)
410 throw new ObjectNotFoundException("No folder specified");
411 User user = dao.getEntityById(User.class, userId);
412 Folder folder = dao.getEntityById(Folder.class, folderId);
413 if (!folder.hasReadPermission(user))
414 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
415 List<FolderDTO> result = new ArrayList<FolderDTO>();
416 if (folder.hasReadPermission(user))
417 for (Folder f : folder.getSubfolders())
418 if (f.hasReadPermission(user) && !f.isDeleted())
419 result.add(f.getDTO());
424 public FolderDTO modifyFolder(Long userId, Long folderId, String folderName)
425 throws InsufficientPermissionsException, ObjectNotFoundException, DuplicateNameException {
429 throw new ObjectNotFoundException("No user specified");
430 if (folderId == null)
431 throw new ObjectNotFoundException("No folder specified");
432 if (StringUtils.isEmpty(folderName))
433 throw new ObjectNotFoundException("New folder name is empty");
435 Folder folder = dao.getEntityById(Folder.class, folderId);
436 User user = dao.getEntityById(User.class, userId);
437 if (!folder.hasWritePermission(user))
438 throw new InsufficientPermissionsException("You don't have the necessary permissions");
440 Folder parent = folder.getParent();
442 if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
443 throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
445 // Do the actual modification.
446 folder.setName(folderName);
448 touchParentFolders(folder, user, new Date());
449 return folder.getDTO();
455 * @see gr.ebs.gss.server.ejb.ExternalAPI#createGroup(java.lang.Long,
458 public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
461 throw new ObjectNotFoundException("No user specified");
462 if (StringUtils.isEmpty(name))
463 throw new ObjectNotFoundException("New group name is empty");
464 if (name.indexOf('/')>=0)
465 throw new IllegalArgumentException("Character '/' is not allowed in group name");
466 if (dao.existsGroup(userId, name))
467 throw new DuplicateNameException("A group with the name '" + name + "' already exists");
469 // TODO: Check permissions
471 final User owner = dao.getEntityById(User.class, userId);
473 // Do the actual work.
474 owner.createGroup(name);
480 * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteGroup(java.lang.Long,
483 public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
486 throw new ObjectNotFoundException("No user specified");
488 throw new ObjectNotFoundException("No group specified");
490 // Do the actual work.
491 final User owner = dao.getEntityById(User.class, userId);
492 final Group group = dao.getEntityById(Group.class, groupId);
493 // Only delete the group if actually owned by the user.
494 if (group.getOwner().equals(owner)) {
495 List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
496 for (Folder f : folders){
497 f.getPermissions().removeAll(group.getPermissions());
498 for(FileHeader file : f.getFiles())
499 file.getPermissions().removeAll(group.getPermissions());
501 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
502 for(FileHeader h : files)
503 h.getPermissions().removeAll(group.getPermissions());
504 owner.removeSpecifiedGroup(group);
507 else throw new InsufficientPermissionsException("You are not the owner of this group");
511 public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
512 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
513 InsufficientPermissionsException, QuotaExceededException {
516 file = uploadFile(stream, userId);
517 } catch ( IOException ioe) {
518 // Supply a more accurate problem description.
519 throw new GSSIOException("Problem creating file",ioe);
521 return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
525 * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
527 public void indexFile(Long fileId, boolean delete) {
528 Connection qConn = null;
529 Session session = null;
530 MessageProducer sender = null;
532 Context jndiCtx = new InitialContext();
533 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
534 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
535 qConn = factory.createConnection();
536 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
537 sender = session.createProducer(queue);
539 MapMessage map = session.createMapMessage();
540 map.setObject("id", fileId);
541 map.setBoolean("delete", delete);
544 catch (NamingException e) {
545 logger.error("Index was not updated: ", e);
547 catch (JMSException e) {
548 logger.error("Index was not updated: ", e);
559 catch (JMSException e) {
568 * A helper method that generates a unique file path for a stored file. The
569 * files are stored using random hash names that are distributed evenly in
570 * a 2-level tree of subdirectories named after the first two hex characters
571 * in the name. For example, file ab1234cd5769f will be stored in the path
572 * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
573 * if they don't already exist.
575 * @return a unique new file path
577 private String generateRepositoryFilePath() {
578 String filename = Long.toHexString(random.nextLong());
579 String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
580 File root = new File(fileRepositoryPath);
583 File firstFolder = new File(root + File.separator + filename.substring(0, 1));
584 if (!firstFolder.exists())
586 File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
587 if (!secondFolder.exists())
588 secondFolder.mkdir();
589 return secondFolder + File.separator + filename;
595 * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFile(java.lang.Long,
598 public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
601 throw new ObjectNotFoundException("No user specified");
603 throw new ObjectNotFoundException("No file specified");
605 // Do the actual work.
606 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
607 final Folder parent = file.getFolder();
609 throw new ObjectNotFoundException("The specified file has no parent folder");
610 final User user = dao.getEntityById(User.class, userId);
611 if (!file.hasDeletePermission(user))
612 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
613 for (final FileBody body : file.getBodies())
614 deleteActualFile(body.getStoredFilePath());
616 touchParentFolders(parent, user, new Date());
617 indexFile(fileId, true);
620 private void deleteActualFile(String filePath) {
621 if (filePath == null)
623 File file = new File(filePath);
625 logger.error("Could not delete file " + filePath);
631 * @see gr.ebs.gss.server.ejb.ExternalAPI#createTag(java.lang.Long,
632 * java.lang.Long, java.lang.String)
634 public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
636 throw new ObjectNotFoundException("No user specified");
637 if (fileHeaderId == null)
638 throw new ObjectNotFoundException("No file specified");
639 if (StringUtils.isEmpty(tag))
640 throw new ObjectNotFoundException("Tag is empty");
642 final User user = dao.getEntityById(User.class, userId);
643 final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
644 final Folder parent = fh.getFolder();
646 throw new ObjectNotFoundException("The specified file has no parent folder");
647 user.addTag(fh, tag);
648 touchParentFolders(parent, user, new Date());
652 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserTags(java.lang.Long)
654 @WebMethod(operationName = "getUserTags")
655 public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
656 return dao.getUserTags(userId);
659 public void updateFile(Long userId, Long fileId, String name,
660 String tagSet, Date modificationDate)
661 throws ObjectNotFoundException, InsufficientPermissionsException {
663 throw new ObjectNotFoundException("No user specified");
665 throw new ObjectNotFoundException("No file specified");
666 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
667 final Folder parent = file.getFolder();
669 throw new ObjectNotFoundException("The specified file has no parent folder");
671 User user = dao.getEntityById(User.class, userId);
672 if (!file.hasWritePermission(user))
673 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
677 if (modificationDate != null) {
678 file.getAuditInfo().setModificationDate(modificationDate);
679 file.getAuditInfo().setModifiedBy(user);
681 List<FileTag> tags = file.getFileTags();
683 if (tagSet != null) {
684 Iterator<FileTag> i = tags.iterator();
685 while (i.hasNext()) {
686 FileTag tag = i.next();
693 StringTokenizer st = new StringTokenizer(tagSet, ",");
694 while (st.hasMoreTokens())
695 new FileTag(user, file, st.nextToken().trim());
697 touchParentFolders(parent, user, new Date());
699 // Re-index the file if it was modified.
700 if (name != null || tagSet != null)
701 indexFile(fileId, false);
705 public InputStream getFileContents(Long userId, Long fileId)
706 throws ObjectNotFoundException, InsufficientPermissionsException {
708 throw new ObjectNotFoundException("No user specified");
710 throw new ObjectNotFoundException("No file specified");
712 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
713 User user = dao.getEntityById(User.class, userId);
714 if (!header.hasReadPermission(user)) {
715 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
716 throw new InsufficientPermissionsException("You don't have the necessary permissions");
719 File f = new File(header.getCurrentBody().getStoredFilePath());
721 return new FileInputStream(f);
722 } catch (FileNotFoundException e) {
723 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
724 throw new ObjectNotFoundException("The file contents could not be located");
729 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
731 public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
733 throw new ObjectNotFoundException("No user specified");
735 throw new ObjectNotFoundException("No file specified");
737 throw new ObjectNotFoundException("No file specified");
739 final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
740 final FileBody body = dao.getEntityById(FileBody.class, bodyId);
741 final User user = dao.getEntityById(User.class, userId);
742 if (!header.hasReadPermission(user)) {
743 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
744 throw new InsufficientPermissionsException("You don't have the necessary permissions");
747 File f = new File(body.getStoredFilePath());
749 return new FileInputStream(f);
750 } catch (FileNotFoundException e) {
751 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
752 throw new ObjectNotFoundException("The file contents could not be located");
757 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFile(java.lang.Long, java.lang.Long)
759 public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
761 throw new ObjectNotFoundException("No user specified");
763 throw new ObjectNotFoundException("No file specified");
764 final User user = dao.getEntityById(User.class, userId);
765 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
766 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
767 throw new InsufficientPermissionsException("You don't have the necessary permissions");
768 return file.getDTO();
772 public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
774 throw new ObjectNotFoundException("No user specified");
776 throw new ObjectNotFoundException("No file specified");
777 User user = dao.getEntityById(User.class, userId);
778 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
779 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
780 throw new InsufficientPermissionsException("You don't have the necessary permissions");
781 FileBody body = dao.getEntityById(FileBody.class, bodyId);
782 return body.getDTO();
786 public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
787 throws ObjectNotFoundException {
789 throw new ObjectNotFoundException("No user specified");
790 if (StringUtils.isEmpty(path))
791 throw new ObjectNotFoundException("No path specified");
793 User owner = dao.getEntityById(User.class, ownerId);
794 List<String> pathElements = new ArrayList<String>();
795 StringTokenizer st = new StringTokenizer(path, "/");
796 while (st.hasMoreTokens())
797 pathElements.add(st.nextToken());
798 if (pathElements.size() < 1)
799 return getRootFolder(owner.getId());
800 // Store the last element, since it requires special handling.
801 String lastElement = pathElements.remove(pathElements.size() - 1);
802 FolderDTO cursor = getRootFolder(owner.getId());
803 // Traverse and verify the specified folder path.
804 for (String pathElement : pathElements) {
805 cursor = getFolder(cursor.getId(), pathElement);
806 if (cursor.isDeleted())
807 throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
810 // Use the lastElement to retrieve the actual resource.
811 Object resource = null;
813 FileHeaderDTO file = getFile(cursor.getId(), lastElement);
814 if (ignoreDeleted && file.isDeleted())
815 throw new ObjectNotFoundException("Resource not found");
817 } catch (ObjectNotFoundException e) {
818 // Perhaps the requested resource is not a file, so
819 // check for folders as well.
820 FolderDTO folder = getFolder(cursor.getId(), lastElement);
821 if (ignoreDeleted && folder.isDeleted())
822 throw new ObjectNotFoundException("Resource not found");
829 * Retrieve a file for the specified user that has the specified name and
830 * its parent folder has id equal to folderId.
832 * @param userId the ID of the current user
833 * @param folderId the ID of the parent folder
834 * @param name the name of the requested file
835 * @return the file found
836 * @throws ObjectNotFoundException if the specified folder or file was not
837 * found, with the exception message mentioning the precise
840 private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
841 if (folderId == null)
842 throw new ObjectNotFoundException("No parent folder specified");
843 if (StringUtils.isEmpty(name))
844 throw new ObjectNotFoundException("No file specified");
846 FileHeader file = dao.getFile(folderId, name);
847 return file.getDTO();
851 * Retrieve a folder for the specified user that has the specified name and
852 * its parent folder has id equal to parentId.
854 * @param parentId the ID of the parent folder
855 * @param name the name of the requested folder
856 * @return the folder found
857 * @throws ObjectNotFoundException if the specified folder or parent was not
858 * found, with the exception message mentioning the precise
861 private FolderDTO getFolder(Long parentId, String name) throws ObjectNotFoundException {
862 if (parentId == null)
863 throw new ObjectNotFoundException("No parent folder specified");
864 if (StringUtils.isEmpty(name))
865 throw new ObjectNotFoundException("No folder specified");
867 Folder folder = dao.getFolder(parentId, name);
868 return folder.getDTO();
871 private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
874 file = uploadFile(resourceInputStream, userId);
875 } catch ( IOException ioe) {
876 // Supply a more accurate problem description.
877 throw new GSSIOException("Problem creating file",ioe);
879 return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
883 public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
885 throw new ObjectNotFoundException("No user specified");
887 throw new ObjectNotFoundException("No file specified");
888 if (StringUtils.isEmpty(dest))
889 throw new ObjectNotFoundException("No destination specified");
891 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
892 if (!(destination instanceof FolderDTO))
893 throw new ObjectNotFoundException("Destination parent folder not found");
894 FolderDTO parent = (FolderDTO) destination;
895 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
899 public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
901 throw new ObjectNotFoundException("No user specified");
903 throw new ObjectNotFoundException("No owner specified");
905 throw new ObjectNotFoundException("No file specified");
906 if (StringUtils.isEmpty(dest))
907 throw new ObjectNotFoundException("No destination specified");
909 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
910 if (!(destination instanceof FolderDTO))
911 throw new ObjectNotFoundException("Destination parent folder not found");
912 FolderDTO parent = (FolderDTO) destination;
913 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
917 public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
919 throw new ObjectNotFoundException("No user specified");
921 throw new ObjectNotFoundException("No file specified");
923 throw new ObjectNotFoundException("No destination specified");
924 if (StringUtils.isEmpty(destName))
925 throw new ObjectNotFoundException("No destination file name specified");
927 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
928 Folder destination = dao.getEntityById(Folder.class, destId);
929 User user = dao.getEntityById(User.class, userId);
930 if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
931 throw new InsufficientPermissionsException("You don't have the necessary permissions");
932 boolean versioned = file.isVersioned();
933 int versionsNumber = file.getBodies().size();
934 FileBody oldestBody = file.getBodies().get(0);
935 assert oldestBody != null;
936 File contents = new File(oldestBody.getStoredFilePath());
938 createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
939 FileHeader copiedFile = dao.getFile(destination.getId(), destName);
940 copiedFile.setVersioned(versioned);
942 if (versionsNumber > 1)
943 for (int i = 1; i < versionsNumber; i++) {
944 FileBody body = file.getBodies().get(i);
946 contents = new File(body.getStoredFilePath());
947 updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
949 List<FileTag> tags = file.getFileTags();
950 for (FileTag tag : tags)
951 createTag(userId, copiedFile.getId(), tag.getTag());
953 } catch (FileNotFoundException e) {
954 throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
960 public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
962 throw new ObjectNotFoundException("No user specified");
963 if (folderId == null)
964 throw new ObjectNotFoundException("No folder specified");
965 if (StringUtils.isEmpty(dest))
966 throw new ObjectNotFoundException("No destination specified");
968 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
969 if (!(destination instanceof FolderDTO))
970 throw new ObjectNotFoundException("Destination folder not found");
971 FolderDTO parent = (FolderDTO) destination;
972 copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
976 public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
978 throw new ObjectNotFoundException("No user specified");
979 if (folderId == null)
980 throw new ObjectNotFoundException("No folder specified");
982 throw new ObjectNotFoundException("No destination specified");
983 if (StringUtils.isEmpty(destName))
984 throw new ObjectNotFoundException("No destination folder name specified");
985 Folder folder = dao.getEntityById(Folder.class, folderId);
986 Folder destination = dao.getEntityById(Folder.class, destId);
987 User user = dao.getEntityById(User.class, userId);
988 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
989 throw new InsufficientPermissionsException("You don't have the necessary permissions");
990 createFolder(user.getId(), destination.getId(), destName);
994 public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
996 throw new ObjectNotFoundException("No user specified");
998 throw new ObjectNotFoundException("No owner specified");
999 if (folderId == null)
1000 throw new ObjectNotFoundException("No folder specified");
1001 if (StringUtils.isEmpty(dest))
1002 throw new ObjectNotFoundException("No destination specified");
1004 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1005 if (!(destination instanceof FolderDTO))
1006 throw new ObjectNotFoundException("Destination folder not found");
1007 FolderDTO parent = (FolderDTO) destination;
1008 copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1012 public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1014 throw new ObjectNotFoundException("No user specified");
1015 if (folderId == null)
1016 throw new ObjectNotFoundException("No folder specified");
1018 throw new ObjectNotFoundException("No destination specified");
1019 if (StringUtils.isEmpty(destName))
1020 throw new ObjectNotFoundException("No destination folder name specified");
1022 Folder folder = dao.getEntityById(Folder.class, folderId);
1023 Folder destination = dao.getEntityById(Folder.class, destId);
1024 final User user = dao.getEntityById(User.class, userId);
1025 // XXX: quick fix need to copy only visible items to user (Source
1027 if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1029 if(folder.isDeleted())//do not copy trashed folder and contents
1031 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1032 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1033 createFolder(user.getId(), destination.getId(), destName);
1034 Folder createdFolder = dao.getFolder(destination.getId(), destName);
1035 List<FileHeader> files = folder.getFiles();
1037 for (FileHeader file : files)
1038 if(!file.isDeleted())
1039 copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1040 List<Folder> subFolders = folder.getSubfolders();
1041 if (subFolders != null)
1042 for (Folder sub : subFolders)
1043 if(!sub.getId().equals(createdFolder.getId()))
1044 copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1049 * For a provided path, remove the last element and return the rest, that is
1050 * the path of the parent folder.
1052 * @param path the specified path
1053 * @return the path of the parent folder
1054 * @throws ObjectNotFoundException if the provided string contains no path
1057 private String getParentPath(String path) throws ObjectNotFoundException {
1058 int lastDelimiter = path.lastIndexOf('/');
1059 if (lastDelimiter == 0)
1061 if (lastDelimiter == -1)
1063 throw new ObjectNotFoundException("There is no parent in the path: " + path);
1064 else if (lastDelimiter < path.length() - 1)
1065 // Return the part before the delimiter.
1066 return path.substring(0, lastDelimiter);
1068 // Remove the trailing delimiter and then recurse.
1069 String strippedTrail = path.substring(0, lastDelimiter);
1070 return getParentPath(strippedTrail);
1075 * Get the last element in a path that denotes the file or folder name.
1077 * @param path the provided path
1078 * @return the last element in the path
1080 private String getLastElement(String path) {
1081 int lastDelimiter = path.lastIndexOf('/');
1082 if (lastDelimiter == -1)
1085 else if (lastDelimiter < path.length() - 1)
1086 // Return the part after the delimiter.
1087 return path.substring(lastDelimiter + 1);
1089 // Remove the trailing delimiter and then recurse.
1090 String strippedTrail = path.substring(0, lastDelimiter);
1091 return getLastElement(strippedTrail);
1096 public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1098 throw new ObjectNotFoundException("No user specified");
1100 throw new ObjectNotFoundException("No file specified");
1102 // Do the actual work.
1103 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1104 Folder parent = file.getFolder();
1106 throw new ObjectNotFoundException("The specified file has no parent folder");
1107 User user = dao.getEntityById(User.class, userId);
1108 if (!file.hasDeletePermission(user))
1109 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1111 file.setDeleted(true);
1113 touchParentFolders(parent, user, new Date());
1117 public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1119 throw new ObjectNotFoundException("No user specified");
1120 if (ownerId == null)
1121 throw new ObjectNotFoundException("No owner specified");
1123 throw new ObjectNotFoundException("No file specified");
1124 if (StringUtils.isEmpty(dest))
1125 throw new ObjectNotFoundException("No destination specified");
1127 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1128 if (!(destination instanceof FolderDTO))
1129 throw new ObjectNotFoundException("Destination parent folder not found");
1130 FolderDTO parent = (FolderDTO) destination;
1131 moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1135 public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1137 throw new ObjectNotFoundException("No user specified");
1139 throw new ObjectNotFoundException("No file specified");
1141 throw new ObjectNotFoundException("No destination specified");
1142 if (StringUtils.isEmpty(destName))
1143 throw new ObjectNotFoundException("No destination file name specified");
1145 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1146 Folder source = file.getFolder();
1147 Folder destination = dao.getEntityById(Folder.class, destId);
1149 User owner = dao.getEntityById(User.class, userId);
1150 if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1151 throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1153 // if the destination folder belongs to another user:
1154 if (!file.getOwner().equals(destination.getOwner())) {
1155 // (a) check if the destination quota allows the move
1156 if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1157 throw new QuotaExceededException("Not enough free space available");
1158 User newOwner = destination.getOwner();
1159 // (b) if quota OK, change the owner of the file
1160 file.setOwner(newOwner);
1161 // if the file has no permission for the new owner, add it
1162 Permission ownerPermission = null;
1163 for (final Permission p : file.getPermissions())
1164 if (p.getUser() != null)
1165 if (p.getUser().equals(newOwner)) {
1166 ownerPermission = p;
1169 if (ownerPermission == null) {
1170 ownerPermission = new Permission();
1171 ownerPermission.setUser(newOwner);
1172 file.addPermission(ownerPermission);
1174 ownerPermission.setRead(true);
1175 ownerPermission.setWrite(true);
1176 ownerPermission.setModifyACL(true);
1178 // move the file to the destination folder
1179 file.setFolder(destination);
1180 touchParentFolders(source, owner, new Date());
1181 touchParentFolders(destination, owner, new Date());
1185 public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1187 throw new ObjectNotFoundException("No user specified");
1188 if (ownerId == null)
1189 throw new ObjectNotFoundException("No owner specified");
1190 if (folderId == null)
1191 throw new ObjectNotFoundException("No folder specified");
1192 if (StringUtils.isEmpty(dest))
1193 throw new ObjectNotFoundException("No destination specified");
1195 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1196 if (!(destination instanceof FolderDTO))
1197 throw new ObjectNotFoundException("Destination parent folder not found");
1198 FolderDTO parent = (FolderDTO) destination;
1199 moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1203 public void moveFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1204 // TODO Simple Move and delete of original folder, in production
1205 // scenario we must first check individual files and folders permissions
1206 copyFolderStructure(userId, folderId, destId, destName);
1207 deleteFolder(userId, folderId);
1211 * @see gr.ebs.gss.server.ejb.ExternalAPI#getDeletedFiles(java.lang.Long)
1213 public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1216 throw new ObjectNotFoundException("No user specified");
1218 // Do the actual work.
1219 final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1220 final List<FileHeader> files = dao.getDeletedFiles(userId);
1221 for (final FileHeader f : files)
1222 result.add(f.getDTO());
1227 public void removeFileFromTrash(Long userId, Long fileId)
1228 throws ObjectNotFoundException, InsufficientPermissionsException {
1230 throw new ObjectNotFoundException("No user specified");
1232 throw new ObjectNotFoundException("No file specified");
1234 // Do the actual work.
1235 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1236 Folder parent = file.getFolder();
1238 throw new ObjectNotFoundException("The specified file has no parent folder");
1239 User user = dao.getEntityById(User.class, userId);
1240 if (!file.hasDeletePermission(user))
1241 throw new InsufficientPermissionsException("User " + user.getUsername() +
1242 " cannot restore file " + file.getName());
1244 file.setDeleted(false);
1246 touchParentFolders(parent, user, new Date());
1250 public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1252 throw new ObjectNotFoundException("No user specified");
1253 if (folderId == null)
1254 throw new ObjectNotFoundException("No folder specified");
1255 Folder folder = dao.getEntityById(Folder.class, folderId);
1256 User user = dao.getEntityById(User.class, userId);
1257 if (!folder.hasDeletePermission(user))
1258 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1259 folder.setDeleted(true);
1261 touchParentFolders(folder, user, new Date());
1262 for (FileHeader file : folder.getFiles())
1263 moveFileToTrash(userId, file.getId());
1264 for (Folder subFolder : folder.getSubfolders())
1265 moveFolderToTrash(userId, subFolder.getId());
1270 public void removeFolderFromTrash(Long userId, Long folderId)
1271 throws ObjectNotFoundException, InsufficientPermissionsException {
1273 throw new ObjectNotFoundException("No user specified");
1274 if (folderId == null)
1275 throw new ObjectNotFoundException("No folder specified");
1276 Folder folder = dao.getEntityById(Folder.class, folderId);
1277 User user = dao.getEntityById(User.class, userId);
1278 if (!folder.hasDeletePermission(user))
1279 throw new InsufficientPermissionsException("User " + user.getUsername() +
1280 " cannot restore folder " + folder.getName());
1281 folder.setDeleted(false);
1282 for (FileHeader file : folder.getFiles())
1283 removeFileFromTrash(userId, file.getId());
1284 for (Folder subFolder : folder.getSubfolders())
1285 removeFolderFromTrash(userId, subFolder.getId());
1287 touchParentFolders(folder, user, new Date());
1291 public List<FolderDTO> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1292 List<Folder> folders = dao.getDeletedRootFolders(userId);
1293 List<FolderDTO> result = new ArrayList<FolderDTO>();
1294 for (Folder folder : folders)
1295 result.add(folder.getDTO());
1300 public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1301 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1302 for (FolderDTO fdto : deletedRootFolders)
1303 deleteFolder(userId, fdto.getId());
1304 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1305 for (FileHeaderDTO filedto : deletedFiles)
1306 deleteFile(userId, filedto.getId());
1310 public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1311 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1312 for (FolderDTO fdto : deletedRootFolders)
1313 removeFolderFromTrash(userId, fdto.getId());
1314 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1315 for (FileHeaderDTO filedto : deletedFiles)
1316 removeFileFromTrash(userId, filedto.getId());
1320 public User createUser(String username, String name, String mail) throws ObjectNotFoundException {
1321 if (username == null)
1322 throw new ObjectNotFoundException("No username specified");
1324 throw new ObjectNotFoundException("No name specified");
1326 User user = new User();
1327 user.setUsername(username);
1329 user.setEmail(mail);
1330 Date now = new Date();
1331 AuditInfo auditInfo = new AuditInfo();
1332 auditInfo.setCreationDate(now);
1333 auditInfo.setModificationDate(now);
1334 user.setAuditInfo(auditInfo);
1335 user.generateAuthToken();
1336 user.generateWebDAVPassword();
1338 // Make sure we get an ID in the user object.
1340 // Create the root folder for the user.
1341 createFolder(user.getName(), null, user);
1346 public User findUserByEmail(String email) {
1347 return dao.findUserByEmail(email);
1351 public void updateUser(User user) {
1356 public User updateUser(String username, String name, String mail) throws ObjectNotFoundException {
1357 if (username == null)
1358 throw new ObjectNotFoundException("No username specified");
1360 User user = dao.getUser(username);
1362 user.setEmail(mail);
1367 public User findUser(String username) {
1368 if (username == null)
1370 return dao.findUser(username);
1374 public User updateUserToken(Long userId) throws ObjectNotFoundException {
1376 throw new ObjectNotFoundException("No user specified");
1377 User user = dao.getEntityById(User.class, userId);
1378 user.generateAuthToken();
1383 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolderPermissions(java.lang.Long, java.lang.Long)
1386 public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1388 throw new ObjectNotFoundException("No user specified");
1389 if (folderId == null)
1390 throw new ObjectNotFoundException("No folder specified");
1391 User user = dao.getEntityById(User.class, userId);
1392 Folder folder = dao.getEntityById(Folder.class, folderId);
1393 if(!folder.hasReadPermission(user))
1394 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1395 Set<Permission> perms = folder.getPermissions();
1396 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1397 for (Permission perm : perms)
1398 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1399 result.add(perm.getDTO());
1400 for (Permission perm : perms)
1401 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1403 result.add(perm.getDTO());
1409 * @see gr.ebs.gss.server.ejb.ExternalAPI#setFolderPermissions(java.lang.Long, java.lang.Long, java.util.Set)
1412 public void setFolderPermissions(Long userId, Long folderId, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1414 throw new ObjectNotFoundException("No user specified");
1415 if (folderId == null)
1416 throw new ObjectNotFoundException("No folder specified");
1417 User user = dao.getEntityById(User.class, userId);
1418 Folder folder = dao.getEntityById(Folder.class, folderId);
1419 if(!folder.hasModifyACLPermission(user))
1420 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1421 // Delete previous entries
1422 for (Permission perm: folder.getPermissions())
1424 folder.getPermissions().clear();
1425 for (PermissionDTO dto : permissions) {
1426 if (dto.getUser()!=null && dto.getUser().getId().equals(folder.getOwner().getId()) && (!dto.hasRead() || !dto.hasWrite() || !dto.hasModifyACL()))
1427 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1428 // Don't include 'empty' permission
1429 if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1430 folder.addPermission(getPermission(dto));
1433 for (FileHeader fh : folder.getFiles())
1434 setFilePermissions(userId, fh.getId(), fh.isReadForAll(), permissions);
1435 for (Folder sub : folder.getSubfolders())
1436 setFolderPermissions(userId, sub.getId(), permissions);
1439 private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1440 Permission res = new Permission();
1441 if (dto.getGroup() != null)
1442 res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1443 else if (dto.getUser() != null)
1444 if (dto.getUser().getId() == null)
1445 res.setUser(dao.getUser(dto.getUser().getUsername()));
1447 res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1448 res.setRead(dto.hasRead());
1449 res.setWrite(dto.hasWrite());
1450 res.setModifyACL(dto.hasModifyACL());
1455 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1458 public List<UserDTO> getUsersByUserNameLike(String username) {
1459 List<User> users = dao.getUsersByUserNameLike(username);
1460 List<UserDTO> result = new ArrayList<UserDTO>();
1461 for (User u : users)
1462 result.add(u.getDTO());
1468 * @see gr.ebs.gss.server.ejb.ExternalAPI#addUserToGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1471 public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1473 throw new ObjectNotFoundException("No user specified");
1474 if (groupId == null)
1475 throw new ObjectNotFoundException("No group specified");
1476 if (userToAddId == null)
1477 throw new ObjectNotFoundException("No user to add specified");
1478 User user = dao.getEntityById(User.class, userId);
1479 Group group = dao.getEntityById(Group.class, groupId);
1480 if (!group.getOwner().equals(user))
1481 throw new InsufficientPermissionsException();
1482 User userToAdd = dao.getEntityById(User.class, userToAddId);
1483 if (group.contains(userToAdd))
1484 throw new DuplicateNameException("User already exists in group");
1485 group.getMembers().add(userToAdd);
1491 public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1493 throw new ObjectNotFoundException("No user specified");
1494 User user = dao.getEntityById(User.class, userId);
1495 user.invalidateAuthToken();
1500 public List<FolderDTO> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1502 throw new ObjectNotFoundException("No user specified");
1503 List<Folder> folders = dao.getSharedRootFolders(userId);
1504 List<FolderDTO> result = new ArrayList<FolderDTO>();
1505 for (Folder f : folders) {
1506 FolderDTO dto = f.getDTO();
1507 dto.setSubfolders(getSharedSubfolders(userId, f.getId()));
1514 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeMemberFromGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1517 public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1519 throw new ObjectNotFoundException("No user specified");
1520 if (groupId == null)
1521 throw new ObjectNotFoundException("No group specified");
1522 if (memberId == null)
1523 throw new ObjectNotFoundException("No member specified");
1524 User owner = dao.getEntityById(User.class, userId);
1525 Group group = dao.getEntityById(Group.class, groupId);
1526 User member = dao.getEntityById(User.class, memberId);
1527 if (!group.getOwner().equals(owner))
1528 throw new InsufficientPermissionsException("User is not the owner of the group");
1529 group.removeMemberFromGroup(member);
1535 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersSharingFoldersForUser(java.lang.Long)
1538 public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1539 List<User> users = dao.getUsersSharingFoldersForUser(userId);
1540 List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1541 List<UserDTO> res = new ArrayList<UserDTO>();
1542 for (User u : users)
1543 res.add(u.getDTO());
1544 for(User fu : usersFiles)
1545 if(!users.contains(fu))
1546 res.add(fu.getDTO());
1551 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFilePermissions(java.lang.Long, java.lang.Long)
1554 public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1556 throw new ObjectNotFoundException("No user specified");
1558 throw new ObjectNotFoundException("No folder specified");
1559 User user = dao.getEntityById(User.class, userId);
1560 FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1561 if(!folder.hasReadPermission(user))
1562 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1563 Set<Permission> perms = folder.getPermissions();
1564 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1565 for (Permission perm : perms)
1566 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1567 result.add(perm.getDTO());
1568 for (Permission perm : perms)
1569 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1571 result.add(perm.getDTO());
1576 public void setFilePermissions(Long userId, Long fileId, Boolean readForAll, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1578 throw new ObjectNotFoundException("No user specified");
1580 throw new ObjectNotFoundException("No folder specified");
1582 User user = dao.getEntityById(User.class, userId);
1583 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1584 if(!file.hasModifyACLPermission(user))
1585 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1587 if (readForAll != null)
1588 if (user.equals(file.getOwner()))
1589 file.setReadForAll(readForAll);
1591 throw new InsufficientPermissionsException("Only the owner can change the read-for-all flag");
1593 // Update the file if there was a change.
1594 if (readForAll != null || permissions != null && !permissions.isEmpty()) {
1595 if (permissions != null && !permissions.isEmpty()) {
1596 // Delete previous entries
1597 for (Permission perm: file.getPermissions())
1599 file.getPermissions().clear();
1600 for (PermissionDTO dto : permissions) {
1601 if (dto.getUser()!=null && dto.getUser().getId().equals(file.getOwner().getId()) && (!dto.hasRead() || !dto.hasWrite() || !dto.hasModifyACL()))
1602 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1603 // Don't include 'empty' permission
1604 if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1605 file.addPermission(getPermission(dto));
1610 Folder parent = file.getFolder();
1611 touchParentFolders(parent, user, new Date());
1616 public List<FileHeaderDTO> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1618 throw new ObjectNotFoundException("No user specified");
1619 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1620 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1621 for (FileHeader f : files)
1622 result.add(f.getDTO());
1627 public List<FileHeaderDTO> getSharedFiles(Long userId) throws ObjectNotFoundException {
1629 throw new ObjectNotFoundException("No user specified");
1630 List<FileHeader> files = dao.getSharedFiles(userId);
1631 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1632 for (FileHeader f : files)
1633 result.add(f.getDTO());
1638 public List<FolderDTO> getSharedFolders(Long userId) throws ObjectNotFoundException {
1640 throw new ObjectNotFoundException("No user specified");
1641 List<Folder> folders = dao.getSharedFolders(userId);
1642 List<FolderDTO> result = new ArrayList<FolderDTO>();
1643 for (Folder f : folders)
1644 result.add(f.getDTO());
1649 * @see gr.ebs.gss.server.ejb.ExternalAPI#getSharedFiles(java.lang.Long, java.lang.Long)
1652 public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1653 if (ownerId == null)
1654 throw new ObjectNotFoundException("No owner specified");
1655 if (callingUserId == null)
1656 throw new ObjectNotFoundException("No calling user specified");
1657 List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1658 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1659 for (FileHeader f : folders)
1660 result.add(f.getDTO());
1665 public List<FolderDTO> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1666 if (ownerId == null)
1667 throw new ObjectNotFoundException("No owner specified");
1668 if (callingUserId == null)
1669 throw new ObjectNotFoundException("No calling user specified");
1670 List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1671 List<FolderDTO> result = new ArrayList<FolderDTO>();
1672 for (Folder f : folders) {
1673 FolderDTO dto = f.getDTO();
1674 dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1682 public List<FolderDTO> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1684 throw new ObjectNotFoundException("No user specified");
1685 if (folderId == null)
1686 throw new ObjectNotFoundException("No folder specified");
1687 User user = dao.getEntityById(User.class, userId);
1688 Folder folder = dao.getEntityById(Folder.class, folderId);
1689 List<FolderDTO> result = new ArrayList<FolderDTO>();
1690 if (folder.isShared(user))
1691 for (Folder f : folder.getSubfolders())
1692 if (f.isShared(user) && !f.isDeleted())
1693 result.add(f.getDTO());
1698 public List<FolderDTO> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1700 throw new ObjectNotFoundException("No user specified");
1701 if (callingUserId == null)
1702 throw new ObjectNotFoundException("No user specified");
1703 if (folderId == null)
1704 throw new ObjectNotFoundException("No folder specified");
1705 User user = dao.getEntityById(User.class, callingUserId);
1706 Folder folder = dao.getEntityById(Folder.class, folderId);
1707 List<FolderDTO> result = new ArrayList<FolderDTO>();
1708 if (folder.isSharedForOtherUser(user))
1709 for (Folder f : folder.getSubfolders())
1710 if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1711 FolderDTO dto = f.getDTO();
1712 dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId()));
1720 * @see gr.ebs.gss.server.ejb.ExternalAPI#searchFiles(java.lang.Long, java.lang.String)
1723 public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1725 throw new ObjectNotFoundException("No user specified");
1726 User user = getUser(userId);
1728 throw new ObjectNotFoundException("No query specified");
1729 List<FileHeader> files = search(user.getId(), query);
1730 List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1731 for(FileHeader f : files)
1732 res.add(f.getDTO());
1737 * Performs the actuals search on the solr server and returns the results
1739 * We have to use the dismax query type (instead of the
1740 * standard) because it allows for search time field boosting. This is because we can't use indexing
1741 * time field boosting due to the patched rich indexing API that does not allow it
1745 * @return a List of FileHeader objects
1747 private List<FileHeader> search(Long userId, String query) {
1749 HttpClient httpClient = new HttpClient();
1751 GetMethod method = new GetMethod(getConfiguration().getString("solrSelectUrl"));
1752 NameValuePair[] params = {new NameValuePair("qt", "dismax"),
1753 new NameValuePair("q", query),
1754 new NameValuePair("sort", "score desc"),
1755 new NameValuePair("indent", "on")};
1756 method.setQueryString(params);
1759 String response = null;
1761 statusCode = httpClient.executeMethod(method);
1762 logger.debug("HTTP status: " + statusCode);
1763 response = method.getResponseBodyAsString();
1764 logger.debug(response);
1766 if (statusCode != 200 && retryCount < 3)
1768 Thread.sleep(3000); //Give Solr a little time to be available
1769 } catch (InterruptedException e) {
1771 } while (statusCode != 200 && retryCount < 3);
1772 if (statusCode != 200)
1773 throw new EJBException("Search query return error:\n" + response);
1775 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1776 DocumentBuilder db = dbf.newDocumentBuilder();
1777 Document doc = db.parse(method.getResponseBodyAsStream());
1778 method.releaseConnection();
1780 Node root = doc.getElementsByTagName("response").item(0);
1781 Node lst = root.getFirstChild().getNextSibling();
1782 Node status = lst.getFirstChild().getNextSibling();
1783 if (status.getAttributes().getNamedItem("name").getNodeValue().equals("status") &&
1784 status.getTextContent().equals("0")) {
1785 List<FileHeader> fileResult = new ArrayList<FileHeader>();
1786 Node result = lst.getNextSibling().getNextSibling();
1787 NodeList docs = result.getChildNodes();
1788 User user = getUser(userId);
1789 for (int i=1; i<docs.getLength(); i=i+2) {
1790 Node d = docs.item(i);
1791 NodeList docData = d.getChildNodes();
1792 for (int j=1; j<docData.getLength(); j=j+2) {
1793 Node dd = docData.item(j);
1794 if (dd.getAttributes().item(0).getNodeName().equals("name") &&
1795 dd.getAttributes().item(0).getNodeValue().equals("id")) {
1796 Long fileId = Long.valueOf(dd.getTextContent());
1798 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1799 if (file.hasReadPermission(user)) {
1800 fileResult.add(file);
1801 logger.debug("File added " + fileId);
1803 } catch (ObjectNotFoundException e) {
1804 logger.warn("Search result not found", e);
1811 throw new EJBException();
1812 } catch (HttpException e) {
1813 throw new EJBException(e);
1814 } catch (IOException e) {
1815 throw new EJBException(e);
1816 } catch (SAXException e) {
1817 throw new EJBException(e);
1818 } catch (ParserConfigurationException e) {
1819 throw new EJBException(e);
1820 } catch (ObjectNotFoundException e) {
1821 throw new EJBException(e);
1826 * @see gr.ebs.gss.server.ejb.ExternalAPI#copyFiles(java.lang.Long, java.util.List, java.lang.Long)
1829 public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1830 for(Long l : fileIds){
1831 FileHeader file = dao.getEntityById(FileHeader.class, l);
1832 copyFile(userId, l, destId, file.getName());
1839 * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFiles(java.lang.Long, java.util.List, java.lang.Long)
1842 public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1843 for(Long l : fileIds){
1844 FileHeader file = dao.getEntityById(FileHeader.class, l);
1845 moveFile(userId, l, destId, file.getName());
1851 * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFiles(java.lang.Long, java.util.List)
1854 public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1856 throw new ObjectNotFoundException("No user specified");
1857 final User user = dao.getEntityById(User.class, userId);
1858 List<String> filesToRemove = new ArrayList<String>();
1859 //first delete database objects
1860 for(Long fileId : fileIds){
1862 throw new ObjectNotFoundException("No file specified");
1863 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1864 final Folder parent = file.getFolder();
1866 throw new ObjectNotFoundException("The specified file has no parent folder");
1867 if (!file.hasDeletePermission(user))
1868 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1870 parent.removeFile(file);
1871 for (final FileBody body : file.getBodies())
1872 filesToRemove.add(body.getStoredFilePath());
1874 touchParentFolders(parent, user, new Date());
1876 //then remove physical files if everything is ok
1877 for(String physicalFileName : filesToRemove)
1878 deleteActualFile(physicalFileName);
1879 //then unindex deleted files
1880 for(Long fileId : fileIds)
1881 indexFile(fileId, true);
1886 * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFilesToTrash(java.lang.Long, java.util.List)
1889 public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1890 for(Long l : fileIds)
1891 moveFileToTrash(userId, l);
1896 public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1897 for(Long l : fileIds)
1898 removeFileFromTrash(userId, l);
1903 public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1905 throw new ObjectNotFoundException("No user specified");
1906 User user = dao.getEntityById(User.class, userId);
1907 Nonce nonce = Nonce.createNonce(user.getId());
1913 public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1915 throw new ObjectNotFoundException("No user specified");
1917 throw new ObjectNotFoundException("No nonce specified");
1918 return dao.getNonce(nonce, userId);
1922 public void removeNonce(Long id) throws ObjectNotFoundException {
1924 throw new ObjectNotFoundException("No nonce specified");
1925 Nonce nonce = dao.getEntityById(Nonce.class, id);
1930 public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1932 throw new ObjectNotFoundException("No user specified");
1933 User user = dao.getEntityById(User.class, userId);
1934 user.setNonce(nonce);
1935 user.setNonceExpiryDate(nonceExpiryDate);
1939 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserStatistics(java.lang.Long)
1942 public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1944 throw new ObjectNotFoundException("No user specified");
1945 StatsDTO stats = new StatsDTO();
1946 stats.setFileCount(dao.getFileCount(userId));
1947 Long fileSize = dao.getFileSize(userId);
1948 stats.setFileSize(fileSize);
1949 Long quota = getQuota(userId);
1950 Long quotaLeft = quota - fileSize;
1951 stats.setQuotaLeftSize(quotaLeft);
1956 * @see gr.ebs.gss.server.ejb.ExternalAPI#getVersions(java.lang.Long, java.lang.Long)
1959 public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1961 throw new ObjectNotFoundException("No user specified");
1963 throw new ObjectNotFoundException("No file specified");
1964 User user = dao.getEntityById(User.class, userId);
1965 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1966 if(!header.hasReadPermission(user))
1967 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1968 List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
1969 for(int i = header.getBodies().size()-1 ; i>=0; i--)
1970 result.add(header.getBodies().get(i).getDTO());
1975 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeVersion(java.lang.Long, java.lang.Long, java.lang.Long)
1978 public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
1980 throw new ObjectNotFoundException("No user specified");
1982 throw new ObjectNotFoundException("No file specified");
1984 throw new ObjectNotFoundException("No body specified");
1985 User user = dao.getEntityById(User.class, userId);
1986 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1987 if(!header.hasWritePermission(user))
1988 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1989 FileBody body = dao.getEntityById(FileBody.class, bodyId);
1990 if(body.equals(header.getCurrentBody())){
1992 if(header.getBodies().size() == 1)
1993 throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
1994 for(FileBody b : header.getBodies())
1995 if(b.getVersion() == body.getVersion()-1)
1996 header.setCurrentBody(b);
1998 deleteActualFile(body.getStoredFilePath());
1999 header.getBodies().remove(body);
2001 Folder parent = header.getFolder();
2002 touchParentFolders(parent, user, new Date());
2007 public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
2009 throw new ObjectNotFoundException("No user specified");
2011 throw new ObjectNotFoundException("No file specified");
2012 User user = dao.getEntityById(User.class, userId);
2013 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2014 if(!header.hasWritePermission(user))
2015 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2016 FileBody body = dao.getFileVersion(fileId, version);
2017 final File fileContents = new File(body.getStoredFilePath());
2020 updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
2021 } catch (FileNotFoundException e) {
2022 throw new GSSIOException(e);
2028 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2031 public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2033 throw new ObjectNotFoundException("No user specified");
2035 throw new ObjectNotFoundException("No file specified");
2036 User user = dao.getEntityById(User.class, userId);
2037 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2038 if(!header.hasWritePermission(user))
2039 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2040 Iterator<FileBody> it = header.getBodies().iterator();
2041 while(it.hasNext()){
2042 FileBody body = it.next();
2043 if(!body.equals(header.getCurrentBody())){
2044 deleteActualFile(body.getStoredFilePath());
2049 header.getCurrentBody().setVersion(1);
2051 Folder parent = header.getFolder();
2052 touchParentFolders(parent, user, new Date());
2056 * @see gr.ebs.gss.server.ejb.ExternalAPI#toggleFileVersioning(java.lang.Long, java.lang.Long, boolean)
2059 public void toggleFileVersioning(Long userId, Long fileId, boolean versioned) throws ObjectNotFoundException, InsufficientPermissionsException {
2061 throw new ObjectNotFoundException("No user specified");
2063 throw new ObjectNotFoundException("No file specified");
2064 User user = dao.getEntityById(User.class, userId);
2065 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2066 if(!header.hasWritePermission(user))
2067 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2068 if(!header.isVersioned() == versioned){
2069 if(header.isVersioned())
2070 removeOldVersions(userId, fileId);
2071 header.setVersioned(versioned);
2072 Folder parent = header.getFolder();
2073 touchParentFolders(parent, user, new Date());
2078 * Gets the quota left for specified userId
2082 private Long getQuotaLeft(Long userId){
2083 Long fileSize = dao.getFileSize(userId);
2084 Long quota = getQuota(userId);
2085 return quota - fileSize;
2089 * Gets the quota for specified userId
2093 private Long getQuota(@SuppressWarnings("unused") Long userId){
2094 Long quota = getConfiguration().getLong("quota", new Long(52428800L));
2098 public void rebuildSolrIndex() {
2099 MessageProducer sender = null;
2100 Session session = null;
2101 Connection qConn = null;
2103 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2104 DocumentBuilder db = dbf.newDocumentBuilder();
2105 Document doc = db.newDocument();
2106 Node root = doc.createElement("delete");
2107 doc.appendChild(root);
2108 Node queryNode = doc.createElement("query");
2109 root.appendChild(queryNode);
2110 queryNode.appendChild(doc.createTextNode("*:*"));
2112 TransformerFactory fact = TransformerFactory.newInstance();
2113 Transformer trans = fact.newTransformer();
2114 trans.setOutputProperty(OutputKeys.INDENT, "yes");
2115 StringWriter sw = new StringWriter();
2116 StreamResult sr = new StreamResult(sw);
2117 DOMSource source = new DOMSource(doc);
2118 trans.transform(source, sr);
2119 logger.debug(sw.toString());
2121 HttpClient httpClient = new HttpClient();
2122 PostMethod method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2123 method.setRequestEntity(new StringRequestEntity(sw.toString()));
2126 String response = null;
2128 statusCode = httpClient.executeMethod(method);
2129 logger.debug("HTTP status: " + statusCode);
2130 response = method.getResponseBodyAsString();
2131 logger.debug(response);
2133 if (statusCode != 200 && retryCount < 3)
2135 Thread.sleep(10000); //Give Solr a little time to be available
2136 } catch (InterruptedException e) {
2138 } while (statusCode != 200 && retryCount < 3);
2139 method.releaseConnection();
2140 if (statusCode != 200)
2141 throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response);
2142 List<Long> fileIds = dao.getAllFileIds();
2144 Context jndiCtx = new InitialContext();
2145 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
2146 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
2147 qConn = factory.createConnection();
2148 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
2149 sender = session.createProducer(queue);
2151 for (Long id : fileIds) {
2152 MapMessage map = session.createMapMessage();
2153 map.setObject("id", id);
2154 map.setBoolean("delete", false);
2157 sendOptimize(httpClient, 0);
2158 } catch (DOMException e) {
2159 throw new EJBException(e);
2160 } catch (TransformerConfigurationException e) {
2161 throw new EJBException(e);
2162 } catch (IllegalArgumentException e) {
2163 throw new EJBException(e);
2164 } catch (HttpException e) {
2165 throw new EJBException(e);
2166 } catch (UnsupportedEncodingException e) {
2167 throw new EJBException(e);
2168 } catch (ParserConfigurationException e) {
2169 throw new EJBException(e);
2170 } catch (TransformerException e) {
2171 throw new EJBException(e);
2172 } catch (IOException e) {
2173 throw new EJBException(e);
2174 } catch (NamingException e) {
2175 throw new EJBException(e);
2176 } catch (JMSException e) {
2177 throw new EJBException(e);
2183 if (session != null)
2188 catch (JMSException e) {
2195 * Sends a optimize message to the solr server
2198 * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive
2199 * calls to stop the recursion
2200 * @throws UnsupportedEncodingException
2201 * @throws IOException
2202 * @throws HttpException
2204 private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException {
2205 PostMethod method = null;
2207 logger.debug("Optimize retry: " + retryCount);
2208 method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2209 method.setRequestEntity(new StringRequestEntity("<optimize/>", "text/xml", "iso8859-1"));
2210 int statusCode = httpClient.executeMethod(method);
2211 logger.debug("HTTP status: " + statusCode);
2212 String response = method.getResponseBodyAsString();
2213 logger.debug(response);
2214 if (statusCode != 200 && retryCount < 2) {
2216 Thread.sleep(10000); //Give Solr a little time to be available
2217 } catch (InterruptedException e) {
2219 sendOptimize(httpClient, retryCount + 1);
2224 method.releaseConnection();
2228 public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2229 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2230 InsufficientPermissionsException, QuotaExceededException {
2233 throw new ObjectNotFoundException("No user specified");
2234 if (folderId == null)
2235 throw new ObjectNotFoundException("No folder specified");
2236 String contentType = mimeType;
2237 if (StringUtils.isEmpty(mimeType))
2238 contentType = DEFAULT_MIME_TYPE;
2239 if (StringUtils.isEmpty(name))
2240 throw new ObjectNotFoundException("No file name specified");
2241 if (dao.existsFolderOrFile(folderId, name))
2242 throw new DuplicateNameException("A folder or file with the name '" + name +
2243 "' already exists at this level");
2245 // Do the actual work.
2246 Folder parent = null;
2248 parent = dao.getEntityById(Folder.class, folderId);
2249 } catch (final ObjectNotFoundException onfe) {
2250 // Supply a more accurate problem description.
2251 throw new ObjectNotFoundException("Parent folder not found");
2253 final User owner = dao.getEntityById(User.class, userId);
2254 if (!parent.hasWritePermission(owner))
2255 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2256 final FileHeader file = new FileHeader();
2258 parent.addFile(file);
2259 // set file owner to folder owner
2260 file.setOwner(parent.getOwner());
2262 final Date now = new Date();
2263 final AuditInfo auditInfo = new AuditInfo();
2264 auditInfo.setCreatedBy(owner);
2265 auditInfo.setCreationDate(now);
2266 auditInfo.setModifiedBy(owner);
2267 auditInfo.setModificationDate(now);
2268 file.setAuditInfo(auditInfo);
2269 // TODO set the proper versioning flag on creation
2270 file.setVersioned(false);
2272 for (final Permission p : parent.getPermissions()) {
2273 final Permission permission = new Permission();
2274 permission.setGroup(p.getGroup());
2275 permission.setUser(p.getUser());
2276 permission.setRead(p.getRead());
2277 permission.setWrite(p.getWrite());
2278 permission.setModifyACL(p.getModifyACL());
2279 file.addPermission(permission);
2282 // Create the file body.
2284 createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2285 } catch (FileNotFoundException e) {
2286 throw new GSSIOException(e);
2288 touchParentFolders(parent, owner, new Date());
2290 indexFile(file.getId(), false);
2292 return file.getDTO();
2296 * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFileContents(java.lang.Long, java.lang.Long, java.lang.String, java.io.InputStream)
2298 public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2300 throw new ObjectNotFoundException("No user specified");
2302 throw new ObjectNotFoundException("No file specified");
2303 String contentType = mimeType;
2305 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2307 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2308 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2309 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2310 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2311 contentType = identifyMimeType(file.getName());
2313 final User owner = dao.getEntityById(User.class, userId);
2314 if (!file.hasWritePermission(owner))
2315 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2316 final Date now = new Date();
2317 final AuditInfo auditInfo = new AuditInfo();
2318 auditInfo.setCreatedBy(owner);
2319 auditInfo.setCreationDate(now);
2320 auditInfo.setModifiedBy(owner);
2321 auditInfo.setModificationDate(now);
2323 createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2324 } catch (FileNotFoundException e) {
2325 throw new GSSIOException(e);
2327 Folder parent = file.getFolder();
2328 touchParentFolders(parent, owner, new Date());
2330 indexFile(fileId, false);
2331 return file.getDTO();
2335 * Helper method for identifying mime type by examining the filename extension
2338 * @return the mime type
2340 private String identifyMimeType(String filename) {
2341 if (filename.indexOf('.') != -1) {
2342 String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2343 if (".doc".equals(extension))
2344 return "application/msword";
2345 else if (".xls".equals(extension))
2346 return "application/vnd.ms-excel";
2347 else if (".ppt".equals(extension))
2348 return "application/vnd.ms-powerpoint";
2349 else if (".pdf".equals(extension))
2350 return "application/pdf";
2351 else if (".gif".equals(extension))
2353 else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2354 return "image/jpeg";
2355 else if (".tiff".equals(extension) || ".tif".equals(extension))
2356 return "image/tiff";
2357 else if (".png".equals(extension))
2359 else if (".bmp".equals(extension))
2362 // when all else fails assign the default mime type
2363 return DEFAULT_MIME_TYPE;
2367 * Helper method to create a new file body and attach it as the current body
2368 * of the provided file header.
2370 * @param name the original file name
2371 * @param mimeType the content type
2372 * @param fileSize the uploaded file size
2373 * @param filePath the uploaded file full path
2374 * @param header the file header that will be associated with the new body
2375 * @param auditInfo the audit info
2376 * @param owner the owner of the file
2377 * @throws FileNotFoundException
2378 * @throws QuotaExceededException
2380 private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2381 FileHeader header, AuditInfo auditInfo)
2382 throws FileNotFoundException, QuotaExceededException {
2384 long currentTotalSize = 0;
2385 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2386 currentTotalSize = header.getTotalSize();
2387 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2388 if(quotaLeft < fileSize-currentTotalSize) {
2389 // quota exceeded -> delete the file
2390 deleteActualFile(filePath);
2391 throw new QuotaExceededException("Not enough free space available");
2394 FileBody body = new FileBody();
2396 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2397 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2398 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2399 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2400 body.setMimeType(identifyMimeType(name));
2402 body.setMimeType(mimeType);
2403 body.setAuditInfo(auditInfo);
2404 body.setFileSize(fileSize);
2405 body.setOriginalFilename(name);
2406 body.setStoredFilePath(filePath);
2407 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2408 if(!header.isVersioned() && header.getCurrentBody() != null){
2409 header.setCurrentBody(null);
2410 if (header.getBodies() != null) {
2411 Iterator<FileBody> it = header.getBodies().iterator();
2412 while(it.hasNext()){
2413 FileBody bo = it.next();
2414 deleteActualFile(bo.getStoredFilePath());
2422 header.addBody(body);
2423 header.setAuditInfo(auditInfo);
2429 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2430 public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2432 throw new ObjectNotFoundException("No user specified");
2433 User owner = dao.getEntityById(User.class, userId);
2435 throw new ObjectNotFoundException("No user specified");
2436 long start = 0, end = 0;
2437 if (logger.isDebugEnabled())
2438 start = System.currentTimeMillis();
2439 File result = new File(generateRepositoryFilePath());
2441 final FileOutputStream output = new FileOutputStream(result);
2442 final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2445 while (-1 != (n = stream.read(buffer)))
2446 output.write(buffer, 0, n);
2449 } catch (IOException e) {
2450 if (!result.delete())
2451 logger.warn("Could not delete " + result.getPath());
2454 if (logger.isDebugEnabled()) {
2455 end = System.currentTimeMillis();
2456 logger.debug("Time to upload: " + (end - start) + " (msec)");
2462 public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2465 throw new ObjectNotFoundException("No user specified");
2466 User user = dao.getEntityById(User.class, userId);
2467 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2469 status = new FileUploadStatus();
2470 status.setOwner(user);
2471 status.setFilename(filename);
2472 status.setBytesUploaded(bytesTransfered);
2473 status.setFileSize(fileSize);
2477 status.setBytesUploaded(bytesTransfered);
2478 status.setFileSize(fileSize);
2484 public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2486 throw new ObjectNotFoundException("No user specified");
2487 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2493 public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2494 return dao.getFileUploadStatus(userId, fileName);
2498 public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2500 throw new ObjectNotFoundException("No user specified");
2501 if (folderId == null)
2502 throw new ObjectNotFoundException("No folder specified");
2503 final User user = dao.getEntityById(User.class, userId);
2504 final Folder folder = dao.getEntityById(Folder.class, folderId);
2505 // Check permissions
2506 if (!folder.hasReadPermission(user))
2507 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2508 List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2509 if (folder.hasReadPermission(user))
2510 for (Folder f : folder.getSubfolders())
2511 if (f.hasReadPermission(user) && !f.isDeleted())
2512 subfolders.add(f.getDTO());
2513 FolderDTO result = folder.getDTO();
2514 result.setSubfolders(subfolders);
2515 return folder.getDTO();
2519 public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2521 throw new ObjectNotFoundException("No user specified");
2522 if (folderId == null)
2523 throw new ObjectNotFoundException("No folder specified");
2524 User user = dao.getEntityById(User.class, callingUserId);
2525 Folder folder = dao.getEntityById(Folder.class, folderId);
2526 // Check permissions
2527 if (!folder.hasReadPermission(user))
2528 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2530 FolderDTO result = folder.getDTO();
2531 result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2536 public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2537 throws ObjectNotFoundException, InsufficientPermissionsException {
2539 throw new ObjectNotFoundException("No user specified");
2541 throw new ObjectNotFoundException("No file specified");
2543 throw new ObjectNotFoundException("No valid version specified");
2544 User user = dao.getEntityById(User.class, userId);
2545 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2546 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2547 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2548 FileBody body = dao.getFileVersion(fileId, version);
2549 return body.getDTO();
2553 public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2555 throw new ObjectNotFoundException("No user specified");
2556 User user = dao.getEntityById(User.class, userId);
2557 user.setAcceptedPolicy(isAccepted);
2562 public void updateAccounting(User user, Date date, long bandwidthDiff) {
2563 dao.updateAccounting(user, date, bandwidthDiff);
2567 public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2569 throw new ObjectNotFoundException("No user specified");
2570 if (folderId == null)
2571 throw new ObjectNotFoundException("No folder specified");
2572 User user = dao.getEntityById(User.class, userId);
2573 Folder folder = dao.getEntityById(Folder.class, folderId);
2574 // Check permissions
2575 if (!folder.hasReadPermission(user))
2581 * Reset WebDAV password for given user.
2584 * @return the new password
2585 * @throws ObjectNotFoundException
2588 public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2590 throw new ObjectNotFoundException("No user specified");
2591 User user = dao.getEntityById(User.class, userId);
2592 user.generateWebDAVPassword();
2593 return user.getWebDAVPassword();