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.naming.Context;
78 import javax.naming.InitialContext;
79 import javax.naming.NamingException;
80 import javax.xml.parsers.DocumentBuilder;
81 import javax.xml.parsers.DocumentBuilderFactory;
82 import javax.xml.parsers.ParserConfigurationException;
83 import javax.xml.transform.OutputKeys;
84 import javax.xml.transform.Transformer;
85 import javax.xml.transform.TransformerConfigurationException;
86 import javax.xml.transform.TransformerException;
87 import javax.xml.transform.TransformerFactory;
88 import javax.xml.transform.dom.DOMSource;
89 import javax.xml.transform.stream.StreamResult;
91 import org.apache.commons.httpclient.HttpClient;
92 import org.apache.commons.httpclient.HttpException;
93 import org.apache.commons.httpclient.NameValuePair;
94 import org.apache.commons.httpclient.methods.GetMethod;
95 import org.apache.commons.httpclient.methods.PostMethod;
96 import org.apache.commons.httpclient.methods.StringRequestEntity;
97 import org.apache.commons.lang.StringUtils;
98 import org.apache.commons.logging.Log;
99 import org.apache.commons.logging.LogFactory;
100 import org.w3c.dom.DOMException;
101 import org.w3c.dom.Document;
102 import org.w3c.dom.Node;
103 import org.w3c.dom.NodeList;
104 import org.xml.sax.SAXException;
107 * The concrete implementation of the ExternalAPI interface.
112 public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
114 * The default MIME type for files without an explicit one.
116 private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
119 * The size of the buffer that is used to temporarily store chunks of
120 * uploaded files, while storing them to the file repository.
122 private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
127 private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
130 * Injected reference to the GSSDAO data access facade.
137 * A cached random number generator for creating unique filenames.
139 private static Random random = new Random();
141 private void touchParentFolders(Folder folder, User modifiedBy, Date modificationDate) {
144 AuditInfo ai = f.getAuditInfo();
145 ai.setModifiedBy(modifiedBy);
146 ai.setModificationDate(modificationDate);
153 public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
155 throw new ObjectNotFoundException("No user specified");
156 Folder folder = dao.getRootFolder(userId);
157 return folder.getDTO();
163 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolder(java.lang.Long)
165 public FolderDTO getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
167 throw new ObjectNotFoundException("No user specified");
168 if (folderId == null)
169 throw new ObjectNotFoundException("No folder specified");
170 final User user = dao.getEntityById(User.class, userId);
171 final Folder folder = dao.getEntityById(Folder.class, folderId);
173 if (!folder.hasReadPermission(user))
174 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
175 return folder.getDTO();
179 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUser(java.lang.Long)
181 public User getUser(Long userId) throws ObjectNotFoundException {
183 throw new ObjectNotFoundException("No user specified");
184 return dao.getEntityById(User.class, userId);
188 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserDTO(java.lang.Long)
190 public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
191 return getUser(userId).getDTO();
197 * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroup(java.lang.Long)
199 public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
201 throw new ObjectNotFoundException("No group specified");
202 final Group group = dao.getEntityById(Group.class, groupId);
203 return group.getDTO();
207 public GroupDTO getGroup(Long userId, String name) throws ObjectNotFoundException {
209 throw new ObjectNotFoundException("No user specified");
211 throw new ObjectNotFoundException("No group specified");
212 User user = dao.getEntityById(User.class, userId);
213 List<Group> groups = user.getGroupsSpecified();
214 for (Group group: groups)
215 if (group.getName().equals(name))
216 return group.getDTO();
217 throw new ObjectNotFoundException("Group " + name + " not found");
223 * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroups(java.lang.Long)
225 public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
227 throw new ObjectNotFoundException("No user specified");
228 final List<Group> groups = dao.getGroups(userId);
229 final List<GroupDTO> result = new ArrayList<GroupDTO>();
230 for (final Group g : groups)
231 result.add(g.getDTO());
236 public List<FileHeaderDTO> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
237 throws ObjectNotFoundException, InsufficientPermissionsException {
240 throw new ObjectNotFoundException("No user specified");
241 if (folderId == null)
242 throw new ObjectNotFoundException("No folder specified");
243 User user = dao.getEntityById(User.class, userId);
244 Folder folder = dao.getEntityById(Folder.class, folderId);
245 if (!folder.hasReadPermission(user))
246 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
247 // Do the actual work.
248 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
249 List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
250 for (FileHeader f : files)
251 result.add(f.getDTO());
258 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsers(java.lang.Long,
261 public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
264 throw new ObjectNotFoundException("No user specified");
266 throw new ObjectNotFoundException("No group specified");
268 // Do the actual work.
269 final List<User> users = dao.getUsers(groupId);
270 final List<UserDTO> result = new ArrayList<UserDTO>();
271 for (final User u : users)
272 result.add(u.getDTO());
277 public FolderDTO createFolder(Long userId, Long parentId, String name)
278 throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
281 throw new ObjectNotFoundException("No user specified");
282 if (StringUtils.isEmpty(name))
283 throw new ObjectNotFoundException("New folder name is empty");
284 if (parentId == null)
285 throw new ObjectNotFoundException("No parent specified");
286 if (dao.existsFolderOrFile(parentId, name))
287 throw new DuplicateNameException("A folder or file with the name '" +
288 name + "' already exists at this level");
290 User creator = dao.getEntityById(User.class, userId);
292 Folder parent = null;
294 parent = dao.getEntityById(Folder.class, parentId);
295 } catch (ObjectNotFoundException onfe) {
296 // Supply a more accurate problem description.
297 throw new ObjectNotFoundException("Parent folder not found");
299 if (!parent.hasWritePermission(creator))
300 throw new InsufficientPermissionsException("You don't have the permissions" +
301 " to write to this folder");
303 // Do the actual work.
304 return createFolder(name, parent, creator);
308 * Create a new folder with the provided name, parent and owner.
313 * @return the new folder
315 private FolderDTO createFolder(String name, Folder parent, User creator) {
316 Folder folder = new Folder();
317 folder.setName(name);
318 if (parent != null) {
319 parent.addSubfolder(folder);
320 folder.setOwner(parent.getOwner());
322 folder.setOwner(creator);
324 Date now = new Date();
325 AuditInfo auditInfo = new AuditInfo();
326 auditInfo.setCreatedBy(creator);
327 auditInfo.setCreationDate(now);
328 auditInfo.setModifiedBy(creator);
329 auditInfo.setModificationDate(now);
330 folder.setAuditInfo(auditInfo);
331 touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
334 for (Permission p : parent.getPermissions()) {
335 Permission permission = new Permission();
336 permission.setGroup(p.getGroup());
337 permission.setUser(p.getUser());
338 permission.setRead(p.getRead());
339 permission.setWrite(p.getWrite());
340 permission.setModifyACL(p.getModifyACL());
341 folder.addPermission(permission);
344 Permission permission = new Permission();
345 permission.setUser(creator);
346 permission.setRead(true);
347 permission.setWrite(true);
348 permission.setModifyACL(true);
349 folder.addPermission(permission);
352 return folder.getDTO();
356 * Deletes the given folder and all its subfolders and files
357 * Only the permissions for top folder are checked
359 * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFolder(java.lang.Long,
362 public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
365 throw new ObjectNotFoundException("No user specified");
366 if (folderId == null)
367 throw new ObjectNotFoundException("No folder specified");
369 // Do the actual work.
370 final Folder folder = dao.getEntityById(Folder.class, folderId);
371 final Folder parent = folder.getParent();
373 throw new ObjectNotFoundException("Deleting the root folder is not allowed");
374 final User user = dao.getEntityById(User.class, userId);
375 if (!folder.hasDeletePermission(user)) {
376 logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
377 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
379 removeSubfolderFiles(folder);
380 parent.removeSubfolder(folder);
382 touchParentFolders(parent, user, new Date());
386 * Traverses the folder and deletes all actual files (file system)
387 * regardless of permissions
391 private void removeSubfolderFiles(Folder folder) {
392 //remove files for all subfolders
393 for (Folder subfolder:folder.getSubfolders())
394 removeSubfolderFiles(subfolder);
395 //remove this folder's file bodies (actual files)
396 for (FileHeader file:folder.getFiles()) {
397 for (FileBody body:file.getBodies())
398 deleteActualFile(body.getStoredFilePath());
399 indexFile(file.getId(), true);
403 @SuppressWarnings("unchecked")
404 public List<FolderDTO> getSubfolders(Long userId, Long folderId)
405 throws ObjectNotFoundException, InsufficientPermissionsException {
407 throw new ObjectNotFoundException("No user specified");
408 if (folderId == null)
409 throw new ObjectNotFoundException("No folder specified");
410 User user = dao.getEntityById(User.class, userId);
411 Folder folder = dao.getEntityById(Folder.class, folderId);
412 if (!folder.hasReadPermission(user))
413 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
414 List<FolderDTO> result = new ArrayList<FolderDTO>();
415 if (folder.hasReadPermission(user))
416 for (Folder f : folder.getSubfolders())
417 if (f.hasReadPermission(user) && !f.isDeleted())
418 result.add(f.getDTO());
423 public FolderDTO updateFolder(Long userId, Long folderId, String folderName,
424 Set<PermissionDTO> permissions)
425 throws InsufficientPermissionsException, ObjectNotFoundException,
426 DuplicateNameException {
430 throw new ObjectNotFoundException("No user specified");
431 if (folderId == null)
432 throw new ObjectNotFoundException("No folder specified");
434 Folder folder = dao.getEntityById(Folder.class, folderId);
435 User user = dao.getEntityById(User.class, userId);
436 if (folderName != null && !folder.hasWritePermission(user))
437 throw new InsufficientPermissionsException("You don't have the necessary permissions");
438 if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
439 throw new InsufficientPermissionsException("You don't have the necessary permissions");
441 Folder parent = folder.getParent();
442 if (folderName != null) {
444 if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
445 throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
447 // Do the actual modification.
448 folder.setName(folderName);
450 if (permissions != null)
451 setFolderPermissions(user, folder, permissions);
453 folder.getAuditInfo().setModificationDate(new Date());
454 folder.getAuditInfo().setModifiedBy(user);
456 touchParentFolders(folder, user, new Date());
457 return folder.getDTO();
463 * @see gr.ebs.gss.server.ejb.ExternalAPI#createGroup(java.lang.Long,
466 public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
469 throw new ObjectNotFoundException("No user specified");
470 if (StringUtils.isEmpty(name))
471 throw new ObjectNotFoundException("New group name is empty");
472 if (name.indexOf('/')>=0)
473 throw new IllegalArgumentException("Character '/' is not allowed in group name");
474 if (dao.existsGroup(userId, name))
475 throw new DuplicateNameException("A group with the name '" + name + "' already exists");
477 // TODO: Check permissions
479 final User owner = dao.getEntityById(User.class, userId);
481 // Do the actual work.
482 owner.createGroup(name);
488 * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteGroup(java.lang.Long,
491 public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
494 throw new ObjectNotFoundException("No user specified");
496 throw new ObjectNotFoundException("No group specified");
498 // Do the actual work.
499 final User owner = dao.getEntityById(User.class, userId);
500 final Group group = dao.getEntityById(Group.class, groupId);
501 // Only delete the group if actually owned by the user.
502 if (group.getOwner().equals(owner)) {
503 List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
504 for (Folder f : folders){
505 f.getPermissions().removeAll(group.getPermissions());
506 for(FileHeader file : f.getFiles())
507 file.getPermissions().removeAll(group.getPermissions());
509 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
510 for(FileHeader h : files)
511 h.getPermissions().removeAll(group.getPermissions());
512 owner.removeSpecifiedGroup(group);
515 else throw new InsufficientPermissionsException("You are not the owner of this group");
519 public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
520 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
521 InsufficientPermissionsException, QuotaExceededException {
524 file = uploadFile(stream, userId);
525 } catch ( IOException ioe) {
526 // Supply a more accurate problem description.
527 throw new GSSIOException("Problem creating file",ioe);
529 return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
533 * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
535 public void indexFile(Long fileId, boolean delete) {
536 Connection qConn = null;
537 Session session = null;
538 MessageProducer sender = null;
540 Context jndiCtx = new InitialContext();
541 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
542 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
543 qConn = factory.createConnection();
544 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
545 sender = session.createProducer(queue);
547 MapMessage map = session.createMapMessage();
548 map.setObject("id", fileId);
549 map.setBoolean("delete", delete);
552 catch (NamingException e) {
553 logger.error("Index was not updated: ", e);
555 catch (JMSException e) {
556 logger.error("Index was not updated: ", e);
567 catch (JMSException e) {
576 * A helper method that generates a unique file path for a stored file. The
577 * files are stored using random hash names that are distributed evenly in
578 * a 2-level tree of subdirectories named after the first two hex characters
579 * in the name. For example, file ab1234cd5769f will be stored in the path
580 * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
581 * if they don't already exist.
583 * @return a unique new file path
585 private String generateRepositoryFilePath() {
586 String filename = Long.toHexString(random.nextLong());
587 String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
588 File root = new File(fileRepositoryPath);
591 File firstFolder = new File(root + File.separator + filename.substring(0, 1));
592 if (!firstFolder.exists())
594 File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
595 if (!secondFolder.exists())
596 secondFolder.mkdir();
597 return secondFolder + File.separator + filename;
603 * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFile(java.lang.Long,
606 public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
609 throw new ObjectNotFoundException("No user specified");
611 throw new ObjectNotFoundException("No file specified");
613 // Do the actual work.
614 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
615 final Folder parent = file.getFolder();
617 throw new ObjectNotFoundException("The specified file has no parent folder");
618 final User user = dao.getEntityById(User.class, userId);
619 if (!file.hasDeletePermission(user))
620 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
621 for (final FileBody body : file.getBodies())
622 deleteActualFile(body.getStoredFilePath());
624 touchParentFolders(parent, user, new Date());
625 indexFile(fileId, true);
628 private void deleteActualFile(String filePath) {
629 if (filePath == null)
631 File file = new File(filePath);
633 logger.error("Could not delete file " + filePath);
636 public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
638 throw new ObjectNotFoundException("No user specified");
639 if (fileHeaderId == null)
640 throw new ObjectNotFoundException("No file specified");
641 if (StringUtils.isEmpty(tag))
642 throw new ObjectNotFoundException("Tag is empty");
644 final User user = dao.getEntityById(User.class, userId);
645 final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
646 final Folder parent = fh.getFolder();
648 throw new ObjectNotFoundException("The specified file has no parent folder");
649 user.addTag(fh, tag);
650 touchParentFolders(parent, user, new Date());
653 public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
654 return dao.getUserTags(userId);
657 public void updateFile(Long userId, Long fileId, String name,
658 String tagSet, Date modificationDate, Boolean versioned,
659 Boolean readForAll, Set<PermissionDTO> permissions)
660 throws ObjectNotFoundException, InsufficientPermissionsException {
662 throw new ObjectNotFoundException("No user specified");
664 throw new ObjectNotFoundException("No file specified");
665 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
666 final Folder parent = file.getFolder();
668 throw new ObjectNotFoundException("The specified file has no parent folder");
670 User user = dao.getEntityById(User.class, userId);
671 // Check permissions for modifying the file metadata.
672 if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
673 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
674 // Check permissions for making file public.
675 if (readForAll != null && !user.equals(file.getOwner()))
676 throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
677 // Check permissions for modifying the ACL.
678 if(permissions != null && !permissions.isEmpty() && !file.hasModifyACLPermission(user))
679 throw new InsufficientPermissionsException("User " + user.getId() + " cannot update the permissions on file " + file.getName() + "(" + file.getId() + ")");
684 if (modificationDate != null)
685 file.getAuditInfo().setModificationDate(modificationDate);
687 file.getAuditInfo().setModificationDate(new Date());
688 file.getAuditInfo().setModifiedBy(user);
690 List<FileTag> tags = file.getFileTags();
691 if (tagSet != null) {
692 Iterator<FileTag> i = tags.iterator();
693 while (i.hasNext()) {
694 FileTag tag = i.next();
701 StringTokenizer st = new StringTokenizer(tagSet, ",");
702 while (st.hasMoreTokens())
703 new FileTag(user, file, st.nextToken().trim());
705 if (versioned != null && !file.isVersioned() == versioned) {
706 if (file.isVersioned())
707 removeOldVersions(userId, fileId);
708 file.setVersioned(versioned);
710 if (readForAll != null && user.equals(file.getOwner()))
711 file.setReadForAll(readForAll);
712 if (permissions != null && !permissions.isEmpty())
713 setFilePermissions(file, permissions);
714 touchParentFolders(parent, user, new Date());
716 // Re-index the file if it was modified.
717 if (name != null || tagSet != null)
718 indexFile(fileId, false);
722 public InputStream getFileContents(Long userId, Long fileId)
723 throws ObjectNotFoundException, InsufficientPermissionsException {
725 throw new ObjectNotFoundException("No user specified");
727 throw new ObjectNotFoundException("No file specified");
729 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
730 User user = dao.getEntityById(User.class, userId);
731 if (!header.hasReadPermission(user)) {
732 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
733 throw new InsufficientPermissionsException("You don't have the necessary permissions");
736 File f = new File(header.getCurrentBody().getStoredFilePath());
738 return new FileInputStream(f);
739 } catch (FileNotFoundException e) {
740 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
741 throw new ObjectNotFoundException("The file contents could not be located");
746 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
748 public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
750 throw new ObjectNotFoundException("No user specified");
752 throw new ObjectNotFoundException("No file specified");
754 throw new ObjectNotFoundException("No file specified");
756 final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
757 final FileBody body = dao.getEntityById(FileBody.class, bodyId);
758 final User user = dao.getEntityById(User.class, userId);
759 if (!header.hasReadPermission(user)) {
760 logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
761 throw new InsufficientPermissionsException("You don't have the necessary permissions");
764 File f = new File(body.getStoredFilePath());
766 return new FileInputStream(f);
767 } catch (FileNotFoundException e) {
768 logger.error("Could not locate the contents of file " + f.getAbsolutePath());
769 throw new ObjectNotFoundException("The file contents could not be located");
774 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFile(java.lang.Long, java.lang.Long)
776 public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
778 throw new ObjectNotFoundException("No user specified");
780 throw new ObjectNotFoundException("No file specified");
781 final User user = dao.getEntityById(User.class, userId);
782 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
783 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
784 throw new InsufficientPermissionsException("You don't have the necessary permissions");
785 return file.getDTO();
789 public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
791 throw new ObjectNotFoundException("No user specified");
793 throw new ObjectNotFoundException("No file specified");
794 User user = dao.getEntityById(User.class, userId);
795 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
796 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
797 throw new InsufficientPermissionsException("You don't have the necessary permissions");
798 FileBody body = dao.getEntityById(FileBody.class, bodyId);
799 return body.getDTO();
803 public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
804 throws ObjectNotFoundException {
806 throw new ObjectNotFoundException("No user specified");
807 if (StringUtils.isEmpty(path))
808 throw new ObjectNotFoundException("No path specified");
810 User owner = dao.getEntityById(User.class, ownerId);
811 List<String> pathElements = new ArrayList<String>();
812 StringTokenizer st = new StringTokenizer(path, "/");
813 while (st.hasMoreTokens())
814 pathElements.add(st.nextToken());
815 if (pathElements.size() < 1)
816 return getRootFolder(owner.getId());
817 // Store the last element, since it requires special handling.
818 String lastElement = pathElements.remove(pathElements.size() - 1);
819 FolderDTO cursor = getRootFolder(owner.getId());
820 // Traverse and verify the specified folder path.
821 for (String pathElement : pathElements) {
822 cursor = getFolder(cursor.getId(), pathElement);
823 if (cursor.isDeleted())
824 throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
827 // Use the lastElement to retrieve the actual resource.
828 Object resource = null;
830 FileHeaderDTO file = getFile(cursor.getId(), lastElement);
831 if (ignoreDeleted && file.isDeleted())
832 throw new ObjectNotFoundException("Resource not found");
834 } catch (ObjectNotFoundException e) {
835 // Perhaps the requested resource is not a file, so
836 // check for folders as well.
837 FolderDTO folder = getFolder(cursor.getId(), lastElement);
838 if (ignoreDeleted && folder.isDeleted())
839 throw new ObjectNotFoundException("Resource not found");
846 * Retrieve a file for the specified user that has the specified name and
847 * its parent folder has id equal to folderId.
849 * @param userId the ID of the current user
850 * @param folderId the ID of the parent folder
851 * @param name the name of the requested file
852 * @return the file found
853 * @throws ObjectNotFoundException if the specified folder or file was not
854 * found, with the exception message mentioning the precise
857 private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
858 if (folderId == null)
859 throw new ObjectNotFoundException("No parent folder specified");
860 if (StringUtils.isEmpty(name))
861 throw new ObjectNotFoundException("No file specified");
863 FileHeader file = dao.getFile(folderId, name);
864 return file.getDTO();
868 * Retrieve a folder for the specified user that has the specified name and
869 * its parent folder has id equal to parentId.
871 * @param parentId the ID of the parent folder
872 * @param name the name of the requested folder
873 * @return the folder found
874 * @throws ObjectNotFoundException if the specified folder or parent was not
875 * found, with the exception message mentioning the precise
878 private FolderDTO getFolder(Long parentId, String name) throws ObjectNotFoundException {
879 if (parentId == null)
880 throw new ObjectNotFoundException("No parent folder specified");
881 if (StringUtils.isEmpty(name))
882 throw new ObjectNotFoundException("No folder specified");
884 Folder folder = dao.getFolder(parentId, name);
885 return folder.getDTO();
888 private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
891 file = uploadFile(resourceInputStream, userId);
892 } catch ( IOException ioe) {
893 // Supply a more accurate problem description.
894 throw new GSSIOException("Problem creating file",ioe);
896 return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
900 public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
902 throw new ObjectNotFoundException("No user specified");
904 throw new ObjectNotFoundException("No file specified");
905 if (StringUtils.isEmpty(dest))
906 throw new ObjectNotFoundException("No destination specified");
908 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
909 if (!(destination instanceof FolderDTO))
910 throw new ObjectNotFoundException("Destination parent folder not found");
911 FolderDTO parent = (FolderDTO) destination;
912 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
916 public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
918 throw new ObjectNotFoundException("No user specified");
920 throw new ObjectNotFoundException("No owner specified");
922 throw new ObjectNotFoundException("No file specified");
923 if (StringUtils.isEmpty(dest))
924 throw new ObjectNotFoundException("No destination specified");
926 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
927 if (!(destination instanceof FolderDTO))
928 throw new ObjectNotFoundException("Destination parent folder not found");
929 FolderDTO parent = (FolderDTO) destination;
930 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
934 public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
936 throw new ObjectNotFoundException("No user specified");
938 throw new ObjectNotFoundException("No file specified");
940 throw new ObjectNotFoundException("No destination specified");
941 if (StringUtils.isEmpty(destName))
942 throw new ObjectNotFoundException("No destination file name specified");
944 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
945 Folder destination = dao.getEntityById(Folder.class, destId);
946 User user = dao.getEntityById(User.class, userId);
947 if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
948 throw new InsufficientPermissionsException("You don't have the necessary permissions");
949 boolean versioned = file.isVersioned();
950 int versionsNumber = file.getBodies().size();
951 FileBody oldestBody = file.getBodies().get(0);
952 assert oldestBody != null;
953 File contents = new File(oldestBody.getStoredFilePath());
955 createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
956 FileHeader copiedFile = dao.getFile(destination.getId(), destName);
957 copiedFile.setVersioned(versioned);
959 if (versionsNumber > 1)
960 for (int i = 1; i < versionsNumber; i++) {
961 FileBody body = file.getBodies().get(i);
963 contents = new File(body.getStoredFilePath());
964 updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
966 List<FileTag> tags = file.getFileTags();
967 for (FileTag tag : tags)
968 createTag(userId, copiedFile.getId(), tag.getTag());
970 } catch (FileNotFoundException e) {
971 throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
977 public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
979 throw new ObjectNotFoundException("No user specified");
980 if (folderId == null)
981 throw new ObjectNotFoundException("No folder specified");
982 if (StringUtils.isEmpty(dest))
983 throw new ObjectNotFoundException("No destination specified");
985 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
986 if (!(destination instanceof FolderDTO))
987 throw new ObjectNotFoundException("Destination folder not found");
988 FolderDTO parent = (FolderDTO) destination;
989 copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
993 public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
995 throw new ObjectNotFoundException("No user specified");
996 if (folderId == null)
997 throw new ObjectNotFoundException("No folder specified");
999 throw new ObjectNotFoundException("No destination specified");
1000 if (StringUtils.isEmpty(destName))
1001 throw new ObjectNotFoundException("No destination folder name specified");
1002 Folder folder = dao.getEntityById(Folder.class, folderId);
1003 Folder destination = dao.getEntityById(Folder.class, destId);
1004 User user = dao.getEntityById(User.class, userId);
1005 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1006 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1007 createFolder(user.getId(), destination.getId(), destName);
1011 public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1013 throw new ObjectNotFoundException("No user specified");
1014 if (ownerId == null)
1015 throw new ObjectNotFoundException("No owner specified");
1016 if (folderId == null)
1017 throw new ObjectNotFoundException("No folder specified");
1018 if (StringUtils.isEmpty(dest))
1019 throw new ObjectNotFoundException("No destination specified");
1021 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1022 if (!(destination instanceof FolderDTO))
1023 throw new ObjectNotFoundException("Destination folder not found");
1024 FolderDTO parent = (FolderDTO) destination;
1025 copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1029 public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1031 throw new ObjectNotFoundException("No user specified");
1032 if (folderId == null)
1033 throw new ObjectNotFoundException("No folder specified");
1035 throw new ObjectNotFoundException("No destination specified");
1036 if (StringUtils.isEmpty(destName))
1037 throw new ObjectNotFoundException("No destination folder name specified");
1039 Folder folder = dao.getEntityById(Folder.class, folderId);
1040 Folder destination = dao.getEntityById(Folder.class, destId);
1041 final User user = dao.getEntityById(User.class, userId);
1042 // XXX: quick fix need to copy only visible items to user (Source
1044 if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1046 if(folder.isDeleted())//do not copy trashed folder and contents
1048 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1049 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1050 createFolder(user.getId(), destination.getId(), destName);
1051 Folder createdFolder = dao.getFolder(destination.getId(), destName);
1052 List<FileHeader> files = folder.getFiles();
1054 for (FileHeader file : files)
1055 if(!file.isDeleted())
1056 copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1057 List<Folder> subFolders = folder.getSubfolders();
1058 if (subFolders != null)
1059 for (Folder sub : subFolders)
1060 if(!sub.getId().equals(createdFolder.getId()))
1061 copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1066 * For a provided path, remove the last element and return the rest, that is
1067 * the path of the parent folder.
1069 * @param path the specified path
1070 * @return the path of the parent folder
1071 * @throws ObjectNotFoundException if the provided string contains no path
1074 private String getParentPath(String path) throws ObjectNotFoundException {
1075 int lastDelimiter = path.lastIndexOf('/');
1076 if (lastDelimiter == 0)
1078 if (lastDelimiter == -1)
1080 throw new ObjectNotFoundException("There is no parent in the path: " + path);
1081 else if (lastDelimiter < path.length() - 1)
1082 // Return the part before the delimiter.
1083 return path.substring(0, lastDelimiter);
1085 // Remove the trailing delimiter and then recurse.
1086 String strippedTrail = path.substring(0, lastDelimiter);
1087 return getParentPath(strippedTrail);
1092 * Get the last element in a path that denotes the file or folder name.
1094 * @param path the provided path
1095 * @return the last element in the path
1097 private String getLastElement(String path) {
1098 int lastDelimiter = path.lastIndexOf('/');
1099 if (lastDelimiter == -1)
1102 else if (lastDelimiter < path.length() - 1)
1103 // Return the part after the delimiter.
1104 return path.substring(lastDelimiter + 1);
1106 // Remove the trailing delimiter and then recurse.
1107 String strippedTrail = path.substring(0, lastDelimiter);
1108 return getLastElement(strippedTrail);
1113 public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1115 throw new ObjectNotFoundException("No user specified");
1117 throw new ObjectNotFoundException("No file specified");
1119 // Do the actual work.
1120 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1121 Folder parent = file.getFolder();
1123 throw new ObjectNotFoundException("The specified file has no parent folder");
1124 User user = dao.getEntityById(User.class, userId);
1125 if (!file.hasDeletePermission(user))
1126 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1128 file.setDeleted(true);
1130 touchParentFolders(parent, user, new Date());
1134 public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1136 throw new ObjectNotFoundException("No user specified");
1137 if (ownerId == null)
1138 throw new ObjectNotFoundException("No owner specified");
1140 throw new ObjectNotFoundException("No file specified");
1141 if (StringUtils.isEmpty(dest))
1142 throw new ObjectNotFoundException("No destination specified");
1144 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1145 if (!(destination instanceof FolderDTO))
1146 throw new ObjectNotFoundException("Destination parent folder not found");
1147 FolderDTO parent = (FolderDTO) destination;
1148 moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1152 public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1154 throw new ObjectNotFoundException("No user specified");
1156 throw new ObjectNotFoundException("No file specified");
1158 throw new ObjectNotFoundException("No destination specified");
1159 if (StringUtils.isEmpty(destName))
1160 throw new ObjectNotFoundException("No destination file name specified");
1162 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1163 Folder source = file.getFolder();
1164 Folder destination = dao.getEntityById(Folder.class, destId);
1166 User owner = dao.getEntityById(User.class, userId);
1167 if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1168 throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1170 // if the destination folder belongs to another user:
1171 if (!file.getOwner().equals(destination.getOwner())) {
1172 // (a) check if the destination quota allows the move
1173 if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1174 throw new QuotaExceededException("Not enough free space available");
1175 User newOwner = destination.getOwner();
1176 // (b) if quota OK, change the owner of the file
1177 file.setOwner(newOwner);
1178 // if the file has no permission for the new owner, add it
1179 Permission ownerPermission = null;
1180 for (final Permission p : file.getPermissions())
1181 if (p.getUser() != null)
1182 if (p.getUser().equals(newOwner)) {
1183 ownerPermission = p;
1186 if (ownerPermission == null) {
1187 ownerPermission = new Permission();
1188 ownerPermission.setUser(newOwner);
1189 file.addPermission(ownerPermission);
1191 ownerPermission.setRead(true);
1192 ownerPermission.setWrite(true);
1193 ownerPermission.setModifyACL(true);
1195 // move the file to the destination folder
1196 file.setFolder(destination);
1197 touchParentFolders(source, owner, new Date());
1198 touchParentFolders(destination, owner, new Date());
1202 public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1204 throw new ObjectNotFoundException("No user specified");
1205 if (ownerId == null)
1206 throw new ObjectNotFoundException("No owner specified");
1207 if (folderId == null)
1208 throw new ObjectNotFoundException("No folder specified");
1209 if (StringUtils.isEmpty(dest))
1210 throw new ObjectNotFoundException("No destination specified");
1212 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1213 if (!(destination instanceof FolderDTO))
1214 throw new ObjectNotFoundException("Destination parent folder not found");
1215 FolderDTO parent = (FolderDTO) destination;
1216 moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1220 public void moveFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1221 // TODO Simple Move and delete of original folder, in production
1222 // scenario we must first check individual files and folders permissions
1223 copyFolderStructure(userId, folderId, destId, destName);
1224 deleteFolder(userId, folderId);
1228 * @see gr.ebs.gss.server.ejb.ExternalAPI#getDeletedFiles(java.lang.Long)
1230 public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1233 throw new ObjectNotFoundException("No user specified");
1235 // Do the actual work.
1236 final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1237 final List<FileHeader> files = dao.getDeletedFiles(userId);
1238 for (final FileHeader f : files)
1239 result.add(f.getDTO());
1244 public void removeFileFromTrash(Long userId, Long fileId)
1245 throws ObjectNotFoundException, InsufficientPermissionsException {
1247 throw new ObjectNotFoundException("No user specified");
1249 throw new ObjectNotFoundException("No file specified");
1251 // Do the actual work.
1252 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1253 Folder parent = file.getFolder();
1255 throw new ObjectNotFoundException("The specified file has no parent folder");
1256 User user = dao.getEntityById(User.class, userId);
1257 if (!file.hasDeletePermission(user))
1258 throw new InsufficientPermissionsException("User " + user.getUsername() +
1259 " cannot restore file " + file.getName());
1261 file.setDeleted(false);
1263 touchParentFolders(parent, user, new Date());
1267 public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1269 throw new ObjectNotFoundException("No user specified");
1270 if (folderId == null)
1271 throw new ObjectNotFoundException("No folder specified");
1272 Folder folder = dao.getEntityById(Folder.class, folderId);
1273 User user = dao.getEntityById(User.class, userId);
1274 if (!folder.hasDeletePermission(user))
1275 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1276 folder.setDeleted(true);
1278 touchParentFolders(folder, user, new Date());
1279 for (FileHeader file : folder.getFiles())
1280 moveFileToTrash(userId, file.getId());
1281 for (Folder subFolder : folder.getSubfolders())
1282 moveFolderToTrash(userId, subFolder.getId());
1287 public void removeFolderFromTrash(Long userId, Long folderId)
1288 throws ObjectNotFoundException, InsufficientPermissionsException {
1290 throw new ObjectNotFoundException("No user specified");
1291 if (folderId == null)
1292 throw new ObjectNotFoundException("No folder specified");
1293 Folder folder = dao.getEntityById(Folder.class, folderId);
1294 User user = dao.getEntityById(User.class, userId);
1295 if (!folder.hasDeletePermission(user))
1296 throw new InsufficientPermissionsException("User " + user.getUsername() +
1297 " cannot restore folder " + folder.getName());
1298 folder.setDeleted(false);
1299 for (FileHeader file : folder.getFiles())
1300 removeFileFromTrash(userId, file.getId());
1301 for (Folder subFolder : folder.getSubfolders())
1302 removeFolderFromTrash(userId, subFolder.getId());
1304 touchParentFolders(folder, user, new Date());
1308 public List<FolderDTO> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1309 List<Folder> folders = dao.getDeletedRootFolders(userId);
1310 List<FolderDTO> result = new ArrayList<FolderDTO>();
1311 for (Folder folder : folders)
1312 result.add(folder.getDTO());
1317 public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1318 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1319 for (FolderDTO fdto : deletedRootFolders)
1320 deleteFolder(userId, fdto.getId());
1321 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1322 for (FileHeaderDTO filedto : deletedFiles)
1323 deleteFile(userId, filedto.getId());
1327 public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1328 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1329 for (FolderDTO fdto : deletedRootFolders)
1330 removeFolderFromTrash(userId, fdto.getId());
1331 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1332 for (FileHeaderDTO filedto : deletedFiles)
1333 removeFileFromTrash(userId, filedto.getId());
1337 public User createUser(String username, String name, String mail) throws ObjectNotFoundException {
1338 if (username == null)
1339 throw new ObjectNotFoundException("No username specified");
1341 throw new ObjectNotFoundException("No name specified");
1343 User user = new User();
1344 user.setUsername(username);
1346 user.setEmail(mail);
1347 Date now = new Date();
1348 AuditInfo auditInfo = new AuditInfo();
1349 auditInfo.setCreationDate(now);
1350 auditInfo.setModificationDate(now);
1351 user.setAuditInfo(auditInfo);
1352 user.generateAuthToken();
1353 user.generateWebDAVPassword();
1355 // Make sure we get an ID in the user object.
1357 // Create the root folder for the user.
1358 createFolder(user.getName(), null, user);
1363 public User findUserByEmail(String email) {
1364 return dao.findUserByEmail(email);
1368 public void updateUser(User user) {
1373 public User updateUser(String username, String name, String mail) throws ObjectNotFoundException {
1374 if (username == null)
1375 throw new ObjectNotFoundException("No username specified");
1377 User user = dao.getUser(username);
1379 user.setEmail(mail);
1384 public User findUser(String username) {
1385 if (username == null)
1387 return dao.findUser(username);
1391 public User updateUserToken(Long userId) throws ObjectNotFoundException {
1393 throw new ObjectNotFoundException("No user specified");
1394 User user = dao.getEntityById(User.class, userId);
1395 user.generateAuthToken();
1400 * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolderPermissions(java.lang.Long, java.lang.Long)
1403 public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1405 throw new ObjectNotFoundException("No user specified");
1406 if (folderId == null)
1407 throw new ObjectNotFoundException("No folder specified");
1408 User user = dao.getEntityById(User.class, userId);
1409 Folder folder = dao.getEntityById(Folder.class, folderId);
1410 if(!folder.hasReadPermission(user))
1411 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1412 Set<Permission> perms = folder.getPermissions();
1413 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1414 for (Permission perm : perms)
1415 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1416 result.add(perm.getDTO());
1417 for (Permission perm : perms)
1418 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1420 result.add(perm.getDTO());
1426 * Set the provided permissions as the new permissions of the specified
1431 * @param permissions
1432 * @throws ObjectNotFoundException
1433 * @throws InsufficientPermissionsException
1435 private void setFolderPermissions(User user, Folder folder, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1436 // Delete previous entries
1437 for (Permission perm: folder.getPermissions())
1439 folder.getPermissions().clear();
1440 for (PermissionDTO dto : permissions) {
1441 if (dto.getUser()!=null && dto.getUser().getId().equals(folder.getOwner().getId()) && (!dto.hasRead() || !dto.hasWrite() || !dto.hasModifyACL()))
1442 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1443 // Don't include 'empty' permission
1444 if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1445 folder.addPermission(getPermission(dto));
1448 for (FileHeader file : folder.getFiles()) {
1449 setFilePermissions(file, permissions);
1450 Date now = new Date();
1451 file.getAuditInfo().setModificationDate(now);
1452 file.getAuditInfo().setModifiedBy(user);
1454 for (Folder sub : folder.getSubfolders())
1455 setFolderPermissions(user, sub, permissions);
1458 private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1459 Permission res = new Permission();
1460 if (dto.getGroup() != null)
1461 res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1462 else if (dto.getUser() != null)
1463 if (dto.getUser().getId() == null)
1464 res.setUser(dao.getUser(dto.getUser().getUsername()));
1466 res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1467 res.setRead(dto.hasRead());
1468 res.setWrite(dto.hasWrite());
1469 res.setModifyACL(dto.hasModifyACL());
1474 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1477 public List<UserDTO> getUsersByUserNameLike(String username) {
1478 List<User> users = dao.getUsersByUserNameLike(username);
1479 List<UserDTO> result = new ArrayList<UserDTO>();
1480 for (User u : users)
1481 result.add(u.getDTO());
1487 * @see gr.ebs.gss.server.ejb.ExternalAPI#addUserToGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1490 public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1492 throw new ObjectNotFoundException("No user specified");
1493 if (groupId == null)
1494 throw new ObjectNotFoundException("No group specified");
1495 if (userToAddId == null)
1496 throw new ObjectNotFoundException("No user to add specified");
1497 User user = dao.getEntityById(User.class, userId);
1498 Group group = dao.getEntityById(Group.class, groupId);
1499 if (!group.getOwner().equals(user))
1500 throw new InsufficientPermissionsException();
1501 User userToAdd = dao.getEntityById(User.class, userToAddId);
1502 if (group.contains(userToAdd))
1503 throw new DuplicateNameException("User already exists in group");
1504 group.getMembers().add(userToAdd);
1510 public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1512 throw new ObjectNotFoundException("No user specified");
1513 User user = dao.getEntityById(User.class, userId);
1514 user.invalidateAuthToken();
1519 public List<FolderDTO> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1521 throw new ObjectNotFoundException("No user specified");
1522 List<Folder> folders = dao.getSharedRootFolders(userId);
1523 List<FolderDTO> result = new ArrayList<FolderDTO>();
1524 for (Folder f : folders) {
1525 FolderDTO dto = f.getDTO();
1526 dto.setSubfolders(getSharedSubfolders(userId, f.getId()));
1533 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeMemberFromGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1536 public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1538 throw new ObjectNotFoundException("No user specified");
1539 if (groupId == null)
1540 throw new ObjectNotFoundException("No group specified");
1541 if (memberId == null)
1542 throw new ObjectNotFoundException("No member specified");
1543 User owner = dao.getEntityById(User.class, userId);
1544 Group group = dao.getEntityById(Group.class, groupId);
1545 User member = dao.getEntityById(User.class, memberId);
1546 if (!group.getOwner().equals(owner))
1547 throw new InsufficientPermissionsException("User is not the owner of the group");
1548 group.removeMemberFromGroup(member);
1554 public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1555 List<User> users = dao.getUsersSharingFoldersForUser(userId);
1556 List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1557 List<UserDTO> res = new ArrayList<UserDTO>();
1558 for (User u : users)
1559 res.add(u.getDTO());
1560 for(User fu : usersFiles)
1561 if(!users.contains(fu))
1562 res.add(fu.getDTO());
1567 public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1569 throw new ObjectNotFoundException("No user specified");
1571 throw new ObjectNotFoundException("No folder specified");
1572 User user = dao.getEntityById(User.class, userId);
1573 FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1574 if(!folder.hasReadPermission(user))
1575 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1576 Set<Permission> perms = folder.getPermissions();
1577 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1578 for (Permission perm : perms)
1579 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1580 result.add(perm.getDTO());
1581 for (Permission perm : perms)
1582 if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1584 result.add(perm.getDTO());
1589 * Set the provided permissions as the new permissions of the specified
1590 * file. This method sets the modification date/user attributes to the
1591 * current values as a side effect.
1594 * @param permissions
1595 * @throws ObjectNotFoundException
1596 * @throws InsufficientPermissionsException
1598 private void setFilePermissions(FileHeader file,
1599 Set<PermissionDTO> permissions)
1600 throws ObjectNotFoundException, InsufficientPermissionsException {
1601 if (permissions != null && !permissions.isEmpty()) {
1602 // Delete previous entries.
1603 for (Permission perm: file.getPermissions())
1605 file.getPermissions().clear();
1606 for (PermissionDTO dto : permissions) {
1607 if (dto.getUser()!=null && dto.getUser().getId().equals(file.getOwner().getId()) && (!dto.hasRead() || !dto.hasWrite() || !dto.hasModifyACL()))
1608 throw new InsufficientPermissionsException("Can't remove permissions from owner");
1609 // Don't include 'empty' permission.
1610 if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1611 file.addPermission(getPermission(dto));
1618 public List<FileHeaderDTO> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1620 throw new ObjectNotFoundException("No user specified");
1621 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1622 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1623 for (FileHeader f : files)
1624 result.add(f.getDTO());
1629 public List<FileHeaderDTO> getSharedFiles(Long userId) throws ObjectNotFoundException {
1631 throw new ObjectNotFoundException("No user specified");
1632 List<FileHeader> files = dao.getSharedFiles(userId);
1633 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1634 for (FileHeader f : files)
1635 result.add(f.getDTO());
1640 public List<FolderDTO> getSharedFolders(Long userId) throws ObjectNotFoundException {
1642 throw new ObjectNotFoundException("No user specified");
1643 List<Folder> folders = dao.getSharedFolders(userId);
1644 List<FolderDTO> result = new ArrayList<FolderDTO>();
1645 for (Folder f : folders)
1646 result.add(f.getDTO());
1651 * @see gr.ebs.gss.server.ejb.ExternalAPI#getSharedFiles(java.lang.Long, java.lang.Long)
1654 public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1655 if (ownerId == null)
1656 throw new ObjectNotFoundException("No owner specified");
1657 if (callingUserId == null)
1658 throw new ObjectNotFoundException("No calling user specified");
1659 List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1660 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1661 for (FileHeader f : folders)
1662 result.add(f.getDTO());
1667 public List<FolderDTO> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1668 if (ownerId == null)
1669 throw new ObjectNotFoundException("No owner specified");
1670 if (callingUserId == null)
1671 throw new ObjectNotFoundException("No calling user specified");
1672 List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1673 List<FolderDTO> result = new ArrayList<FolderDTO>();
1674 for (Folder f : folders) {
1675 FolderDTO dto = f.getDTO();
1676 dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1684 public List<FolderDTO> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1686 throw new ObjectNotFoundException("No user specified");
1687 if (folderId == null)
1688 throw new ObjectNotFoundException("No folder specified");
1689 User user = dao.getEntityById(User.class, userId);
1690 Folder folder = dao.getEntityById(Folder.class, folderId);
1691 List<FolderDTO> result = new ArrayList<FolderDTO>();
1692 if (folder.isShared(user))
1693 for (Folder f : folder.getSubfolders())
1694 if (f.isShared(user) && !f.isDeleted())
1695 result.add(f.getDTO());
1700 public List<FolderDTO> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1702 throw new ObjectNotFoundException("No user specified");
1703 if (callingUserId == null)
1704 throw new ObjectNotFoundException("No user specified");
1705 if (folderId == null)
1706 throw new ObjectNotFoundException("No folder specified");
1707 User user = dao.getEntityById(User.class, callingUserId);
1708 Folder folder = dao.getEntityById(Folder.class, folderId);
1709 List<FolderDTO> result = new ArrayList<FolderDTO>();
1710 if (folder.isSharedForOtherUser(user))
1711 for (Folder f : folder.getSubfolders())
1712 if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1713 FolderDTO dto = f.getDTO();
1714 dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId()));
1722 * @see gr.ebs.gss.server.ejb.ExternalAPI#searchFiles(java.lang.Long, java.lang.String)
1725 public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1727 throw new ObjectNotFoundException("No user specified");
1728 User user = getUser(userId);
1730 throw new ObjectNotFoundException("No query specified");
1731 List<FileHeader> files = search(user.getId(), query);
1732 List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1733 for(FileHeader f : files)
1734 res.add(f.getDTO());
1739 * Performs the actuals search on the solr server and returns the results
1741 * We have to use the dismax query type (instead of the
1742 * standard) because it allows for search time field boosting. This is because we can't use indexing
1743 * time field boosting due to the patched rich indexing API that does not allow it
1747 * @return a List of FileHeader objects
1749 private List<FileHeader> search(Long userId, String query) {
1751 HttpClient httpClient = new HttpClient();
1753 GetMethod method = new GetMethod(getConfiguration().getString("solrSelectUrl"));
1754 NameValuePair[] params = {new NameValuePair("qt", "dismax"),
1755 new NameValuePair("q", query),
1756 new NameValuePair("sort", "score desc"),
1757 new NameValuePair("indent", "on")};
1758 method.setQueryString(params);
1761 String response = null;
1763 statusCode = httpClient.executeMethod(method);
1764 logger.debug("HTTP status: " + statusCode);
1765 response = method.getResponseBodyAsString();
1766 logger.debug(response);
1768 if (statusCode != 200 && retryCount < 3)
1770 Thread.sleep(3000); //Give Solr a little time to be available
1771 } catch (InterruptedException e) {
1773 } while (statusCode != 200 && retryCount < 3);
1774 if (statusCode != 200)
1775 throw new EJBException("Search query return error:\n" + response);
1777 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1778 DocumentBuilder db = dbf.newDocumentBuilder();
1779 Document doc = db.parse(method.getResponseBodyAsStream());
1780 method.releaseConnection();
1782 Node root = doc.getElementsByTagName("response").item(0);
1783 Node lst = root.getFirstChild().getNextSibling();
1784 Node status = lst.getFirstChild().getNextSibling();
1785 if (status.getAttributes().getNamedItem("name").getNodeValue().equals("status") &&
1786 status.getTextContent().equals("0")) {
1787 List<FileHeader> fileResult = new ArrayList<FileHeader>();
1788 Node result = lst.getNextSibling().getNextSibling();
1789 NodeList docs = result.getChildNodes();
1790 User user = getUser(userId);
1791 for (int i=1; i<docs.getLength(); i=i+2) {
1792 Node d = docs.item(i);
1793 NodeList docData = d.getChildNodes();
1794 for (int j=1; j<docData.getLength(); j=j+2) {
1795 Node dd = docData.item(j);
1796 if (dd.getAttributes().item(0).getNodeName().equals("name") &&
1797 dd.getAttributes().item(0).getNodeValue().equals("id")) {
1798 Long fileId = Long.valueOf(dd.getTextContent());
1800 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1801 if (file.hasReadPermission(user)) {
1802 fileResult.add(file);
1803 logger.debug("File added " + fileId);
1805 } catch (ObjectNotFoundException e) {
1806 logger.warn("Search result not found", e);
1813 throw new EJBException();
1814 } catch (HttpException e) {
1815 throw new EJBException(e);
1816 } catch (IOException e) {
1817 throw new EJBException(e);
1818 } catch (SAXException e) {
1819 throw new EJBException(e);
1820 } catch (ParserConfigurationException e) {
1821 throw new EJBException(e);
1822 } catch (ObjectNotFoundException e) {
1823 throw new EJBException(e);
1828 * @see gr.ebs.gss.server.ejb.ExternalAPI#copyFiles(java.lang.Long, java.util.List, java.lang.Long)
1831 public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1832 for(Long l : fileIds){
1833 FileHeader file = dao.getEntityById(FileHeader.class, l);
1834 copyFile(userId, l, destId, file.getName());
1841 * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFiles(java.lang.Long, java.util.List, java.lang.Long)
1844 public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1845 for(Long l : fileIds){
1846 FileHeader file = dao.getEntityById(FileHeader.class, l);
1847 moveFile(userId, l, destId, file.getName());
1853 * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFiles(java.lang.Long, java.util.List)
1856 public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1858 throw new ObjectNotFoundException("No user specified");
1859 final User user = dao.getEntityById(User.class, userId);
1860 List<String> filesToRemove = new ArrayList<String>();
1861 //first delete database objects
1862 for(Long fileId : fileIds){
1864 throw new ObjectNotFoundException("No file specified");
1865 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1866 final Folder parent = file.getFolder();
1868 throw new ObjectNotFoundException("The specified file has no parent folder");
1869 if (!file.hasDeletePermission(user))
1870 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1872 parent.removeFile(file);
1873 for (final FileBody body : file.getBodies())
1874 filesToRemove.add(body.getStoredFilePath());
1876 touchParentFolders(parent, user, new Date());
1878 //then remove physical files if everything is ok
1879 for(String physicalFileName : filesToRemove)
1880 deleteActualFile(physicalFileName);
1881 //then unindex deleted files
1882 for(Long fileId : fileIds)
1883 indexFile(fileId, true);
1888 * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFilesToTrash(java.lang.Long, java.util.List)
1891 public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1892 for(Long l : fileIds)
1893 moveFileToTrash(userId, l);
1898 public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1899 for(Long l : fileIds)
1900 removeFileFromTrash(userId, l);
1905 public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1907 throw new ObjectNotFoundException("No user specified");
1908 User user = dao.getEntityById(User.class, userId);
1909 Nonce nonce = Nonce.createNonce(user.getId());
1915 public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1917 throw new ObjectNotFoundException("No user specified");
1919 throw new ObjectNotFoundException("No nonce specified");
1920 return dao.getNonce(nonce, userId);
1924 public void removeNonce(Long id) throws ObjectNotFoundException {
1926 throw new ObjectNotFoundException("No nonce specified");
1927 Nonce nonce = dao.getEntityById(Nonce.class, id);
1932 public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1934 throw new ObjectNotFoundException("No user specified");
1935 User user = dao.getEntityById(User.class, userId);
1936 user.setNonce(nonce);
1937 user.setNonceExpiryDate(nonceExpiryDate);
1941 * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserStatistics(java.lang.Long)
1944 public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1946 throw new ObjectNotFoundException("No user specified");
1947 StatsDTO stats = new StatsDTO();
1948 stats.setFileCount(dao.getFileCount(userId));
1949 Long fileSize = dao.getFileSize(userId);
1950 stats.setFileSize(fileSize);
1951 Long quota = getQuota(userId);
1952 Long quotaLeft = quota - fileSize;
1953 stats.setQuotaLeftSize(quotaLeft);
1958 * @see gr.ebs.gss.server.ejb.ExternalAPI#getVersions(java.lang.Long, java.lang.Long)
1961 public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1963 throw new ObjectNotFoundException("No user specified");
1965 throw new ObjectNotFoundException("No file specified");
1966 User user = dao.getEntityById(User.class, userId);
1967 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1968 if(!header.hasReadPermission(user))
1969 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1970 List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
1971 for(int i = header.getBodies().size()-1 ; i>=0; i--)
1972 result.add(header.getBodies().get(i).getDTO());
1977 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeVersion(java.lang.Long, java.lang.Long, java.lang.Long)
1980 public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
1982 throw new ObjectNotFoundException("No user specified");
1984 throw new ObjectNotFoundException("No file specified");
1986 throw new ObjectNotFoundException("No body specified");
1987 User user = dao.getEntityById(User.class, userId);
1988 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1989 if(!header.hasWritePermission(user))
1990 throw new InsufficientPermissionsException("You don't have the necessary permissions");
1991 FileBody body = dao.getEntityById(FileBody.class, bodyId);
1992 if(body.equals(header.getCurrentBody())){
1994 if(header.getBodies().size() == 1)
1995 throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
1996 for(FileBody b : header.getBodies())
1997 if(b.getVersion() == body.getVersion()-1)
1998 header.setCurrentBody(b);
2000 deleteActualFile(body.getStoredFilePath());
2001 header.getBodies().remove(body);
2003 Folder parent = header.getFolder();
2004 touchParentFolders(parent, user, new Date());
2009 public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
2011 throw new ObjectNotFoundException("No user specified");
2013 throw new ObjectNotFoundException("No file specified");
2014 User user = dao.getEntityById(User.class, userId);
2015 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2016 if(!header.hasWritePermission(user))
2017 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2018 FileBody body = dao.getFileVersion(fileId, version);
2019 final File fileContents = new File(body.getStoredFilePath());
2022 updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
2023 } catch (FileNotFoundException e) {
2024 throw new GSSIOException(e);
2030 * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2033 public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2035 throw new ObjectNotFoundException("No user specified");
2037 throw new ObjectNotFoundException("No file specified");
2038 User user = dao.getEntityById(User.class, userId);
2039 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2040 if(!header.hasWritePermission(user))
2041 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2042 Iterator<FileBody> it = header.getBodies().iterator();
2043 while(it.hasNext()){
2044 FileBody body = it.next();
2045 if(!body.equals(header.getCurrentBody())){
2046 deleteActualFile(body.getStoredFilePath());
2051 header.getCurrentBody().setVersion(1);
2053 Folder parent = header.getFolder();
2054 touchParentFolders(parent, user, new Date());
2058 * Gets the quota left for specified userId
2062 private Long getQuotaLeft(Long userId){
2063 Long fileSize = dao.getFileSize(userId);
2064 Long quota = getQuota(userId);
2065 return quota - fileSize;
2069 * Gets the quota for specified userId
2073 private Long getQuota(@SuppressWarnings("unused") Long userId){
2074 Long quota = getConfiguration().getLong("quota", new Long(52428800L));
2078 public void rebuildSolrIndex() {
2079 MessageProducer sender = null;
2080 Session session = null;
2081 Connection qConn = null;
2083 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2084 DocumentBuilder db = dbf.newDocumentBuilder();
2085 Document doc = db.newDocument();
2086 Node root = doc.createElement("delete");
2087 doc.appendChild(root);
2088 Node queryNode = doc.createElement("query");
2089 root.appendChild(queryNode);
2090 queryNode.appendChild(doc.createTextNode("*:*"));
2092 TransformerFactory fact = TransformerFactory.newInstance();
2093 Transformer trans = fact.newTransformer();
2094 trans.setOutputProperty(OutputKeys.INDENT, "yes");
2095 StringWriter sw = new StringWriter();
2096 StreamResult sr = new StreamResult(sw);
2097 DOMSource source = new DOMSource(doc);
2098 trans.transform(source, sr);
2099 logger.debug(sw.toString());
2101 HttpClient httpClient = new HttpClient();
2102 PostMethod method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2103 method.setRequestEntity(new StringRequestEntity(sw.toString()));
2106 String response = null;
2108 statusCode = httpClient.executeMethod(method);
2109 logger.debug("HTTP status: " + statusCode);
2110 response = method.getResponseBodyAsString();
2111 logger.debug(response);
2113 if (statusCode != 200 && retryCount < 3)
2115 Thread.sleep(10000); //Give Solr a little time to be available
2116 } catch (InterruptedException e) {
2118 } while (statusCode != 200 && retryCount < 3);
2119 method.releaseConnection();
2120 if (statusCode != 200)
2121 throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response);
2122 List<Long> fileIds = dao.getAllFileIds();
2124 Context jndiCtx = new InitialContext();
2125 ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
2126 Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
2127 qConn = factory.createConnection();
2128 session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
2129 sender = session.createProducer(queue);
2131 for (Long id : fileIds) {
2132 MapMessage map = session.createMapMessage();
2133 map.setObject("id", id);
2134 map.setBoolean("delete", false);
2137 sendOptimize(httpClient, 0);
2138 } catch (DOMException e) {
2139 throw new EJBException(e);
2140 } catch (TransformerConfigurationException e) {
2141 throw new EJBException(e);
2142 } catch (IllegalArgumentException e) {
2143 throw new EJBException(e);
2144 } catch (HttpException e) {
2145 throw new EJBException(e);
2146 } catch (UnsupportedEncodingException e) {
2147 throw new EJBException(e);
2148 } catch (ParserConfigurationException e) {
2149 throw new EJBException(e);
2150 } catch (TransformerException e) {
2151 throw new EJBException(e);
2152 } catch (IOException e) {
2153 throw new EJBException(e);
2154 } catch (NamingException e) {
2155 throw new EJBException(e);
2156 } catch (JMSException e) {
2157 throw new EJBException(e);
2163 if (session != null)
2168 catch (JMSException e) {
2175 * Sends a optimize message to the solr server
2178 * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive
2179 * calls to stop the recursion
2180 * @throws UnsupportedEncodingException
2181 * @throws IOException
2182 * @throws HttpException
2184 private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException {
2185 PostMethod method = null;
2187 logger.debug("Optimize retry: " + retryCount);
2188 method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2189 method.setRequestEntity(new StringRequestEntity("<optimize/>", "text/xml", "iso8859-1"));
2190 int statusCode = httpClient.executeMethod(method);
2191 logger.debug("HTTP status: " + statusCode);
2192 String response = method.getResponseBodyAsString();
2193 logger.debug(response);
2194 if (statusCode != 200 && retryCount < 2) {
2196 Thread.sleep(10000); //Give Solr a little time to be available
2197 } catch (InterruptedException e) {
2199 sendOptimize(httpClient, retryCount + 1);
2204 method.releaseConnection();
2208 public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2209 throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2210 InsufficientPermissionsException, QuotaExceededException {
2213 throw new ObjectNotFoundException("No user specified");
2214 if (folderId == null)
2215 throw new ObjectNotFoundException("No folder specified");
2216 String contentType = mimeType;
2217 if (StringUtils.isEmpty(mimeType))
2218 contentType = DEFAULT_MIME_TYPE;
2219 if (StringUtils.isEmpty(name))
2220 throw new ObjectNotFoundException("No file name specified");
2221 if (dao.existsFolderOrFile(folderId, name))
2222 throw new DuplicateNameException("A folder or file with the name '" + name +
2223 "' already exists at this level");
2225 // Do the actual work.
2226 Folder parent = null;
2228 parent = dao.getEntityById(Folder.class, folderId);
2229 } catch (final ObjectNotFoundException onfe) {
2230 // Supply a more accurate problem description.
2231 throw new ObjectNotFoundException("Parent folder not found");
2233 final User owner = dao.getEntityById(User.class, userId);
2234 if (!parent.hasWritePermission(owner))
2235 throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2236 final FileHeader file = new FileHeader();
2238 parent.addFile(file);
2239 // set file owner to folder owner
2240 file.setOwner(parent.getOwner());
2242 final Date now = new Date();
2243 final AuditInfo auditInfo = new AuditInfo();
2244 auditInfo.setCreatedBy(owner);
2245 auditInfo.setCreationDate(now);
2246 auditInfo.setModifiedBy(owner);
2247 auditInfo.setModificationDate(now);
2248 file.setAuditInfo(auditInfo);
2249 // TODO set the proper versioning flag on creation
2250 file.setVersioned(false);
2252 for (final Permission p : parent.getPermissions()) {
2253 final Permission permission = new Permission();
2254 permission.setGroup(p.getGroup());
2255 permission.setUser(p.getUser());
2256 permission.setRead(p.getRead());
2257 permission.setWrite(p.getWrite());
2258 permission.setModifyACL(p.getModifyACL());
2259 file.addPermission(permission);
2262 // Create the file body.
2264 createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2265 } catch (FileNotFoundException e) {
2266 throw new GSSIOException(e);
2268 touchParentFolders(parent, owner, new Date());
2270 indexFile(file.getId(), false);
2272 return file.getDTO();
2276 * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFileContents(java.lang.Long, java.lang.Long, java.lang.String, java.io.InputStream)
2278 public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2280 throw new ObjectNotFoundException("No user specified");
2282 throw new ObjectNotFoundException("No file specified");
2283 String contentType = mimeType;
2285 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2287 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2288 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2289 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2290 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2291 contentType = identifyMimeType(file.getName());
2293 final User owner = dao.getEntityById(User.class, userId);
2294 if (!file.hasWritePermission(owner))
2295 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2296 final Date now = new Date();
2297 final AuditInfo auditInfo = new AuditInfo();
2298 auditInfo.setCreatedBy(owner);
2299 auditInfo.setCreationDate(now);
2300 auditInfo.setModifiedBy(owner);
2301 auditInfo.setModificationDate(now);
2303 createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2304 } catch (FileNotFoundException e) {
2305 throw new GSSIOException(e);
2307 Folder parent = file.getFolder();
2308 touchParentFolders(parent, owner, new Date());
2310 indexFile(fileId, false);
2311 return file.getDTO();
2315 * Helper method for identifying mime type by examining the filename extension
2318 * @return the mime type
2320 private String identifyMimeType(String filename) {
2321 if (filename.indexOf('.') != -1) {
2322 String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2323 if (".doc".equals(extension))
2324 return "application/msword";
2325 else if (".xls".equals(extension))
2326 return "application/vnd.ms-excel";
2327 else if (".ppt".equals(extension))
2328 return "application/vnd.ms-powerpoint";
2329 else if (".pdf".equals(extension))
2330 return "application/pdf";
2331 else if (".gif".equals(extension))
2333 else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2334 return "image/jpeg";
2335 else if (".tiff".equals(extension) || ".tif".equals(extension))
2336 return "image/tiff";
2337 else if (".png".equals(extension))
2339 else if (".bmp".equals(extension))
2342 // when all else fails assign the default mime type
2343 return DEFAULT_MIME_TYPE;
2347 * Helper method to create a new file body and attach it as the current body
2348 * of the provided file header.
2350 * @param name the original file name
2351 * @param mimeType the content type
2352 * @param fileSize the uploaded file size
2353 * @param filePath the uploaded file full path
2354 * @param header the file header that will be associated with the new body
2355 * @param auditInfo the audit info
2356 * @param owner the owner of the file
2357 * @throws FileNotFoundException
2358 * @throws QuotaExceededException
2360 private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2361 FileHeader header, AuditInfo auditInfo)
2362 throws FileNotFoundException, QuotaExceededException {
2364 long currentTotalSize = 0;
2365 if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2366 currentTotalSize = header.getTotalSize();
2367 Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2368 if(quotaLeft < fileSize-currentTotalSize) {
2369 // quota exceeded -> delete the file
2370 deleteActualFile(filePath);
2371 throw new QuotaExceededException("Not enough free space available");
2374 FileBody body = new FileBody();
2376 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2377 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2378 || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2379 || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2380 body.setMimeType(identifyMimeType(name));
2382 body.setMimeType(mimeType);
2383 body.setAuditInfo(auditInfo);
2384 body.setFileSize(fileSize);
2385 body.setOriginalFilename(name);
2386 body.setStoredFilePath(filePath);
2387 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2388 if(!header.isVersioned() && header.getCurrentBody() != null){
2389 header.setCurrentBody(null);
2390 if (header.getBodies() != null) {
2391 Iterator<FileBody> it = header.getBodies().iterator();
2392 while(it.hasNext()){
2393 FileBody bo = it.next();
2394 deleteActualFile(bo.getStoredFilePath());
2402 header.addBody(body);
2403 header.setAuditInfo(auditInfo);
2409 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2410 public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2412 throw new ObjectNotFoundException("No user specified");
2413 User owner = dao.getEntityById(User.class, userId);
2415 throw new ObjectNotFoundException("No user specified");
2416 long start = 0, end = 0;
2417 if (logger.isDebugEnabled())
2418 start = System.currentTimeMillis();
2419 File result = new File(generateRepositoryFilePath());
2421 final FileOutputStream output = new FileOutputStream(result);
2422 final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2425 while (-1 != (n = stream.read(buffer)))
2426 output.write(buffer, 0, n);
2429 } catch (IOException e) {
2430 if (!result.delete())
2431 logger.warn("Could not delete " + result.getPath());
2434 if (logger.isDebugEnabled()) {
2435 end = System.currentTimeMillis();
2436 logger.debug("Time to upload: " + (end - start) + " (msec)");
2442 public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2445 throw new ObjectNotFoundException("No user specified");
2446 User user = dao.getEntityById(User.class, userId);
2447 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2449 status = new FileUploadStatus();
2450 status.setOwner(user);
2451 status.setFilename(filename);
2452 status.setBytesUploaded(bytesTransfered);
2453 status.setFileSize(fileSize);
2457 status.setBytesUploaded(bytesTransfered);
2458 status.setFileSize(fileSize);
2464 public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2466 throw new ObjectNotFoundException("No user specified");
2467 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2473 public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2474 return dao.getFileUploadStatus(userId, fileName);
2478 public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2480 throw new ObjectNotFoundException("No user specified");
2481 if (folderId == null)
2482 throw new ObjectNotFoundException("No folder specified");
2483 final User user = dao.getEntityById(User.class, userId);
2484 final Folder folder = dao.getEntityById(Folder.class, folderId);
2485 // Check permissions
2486 if (!folder.hasReadPermission(user))
2487 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2488 List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2489 if (folder.hasReadPermission(user))
2490 for (Folder f : folder.getSubfolders())
2491 if (f.hasReadPermission(user) && !f.isDeleted())
2492 subfolders.add(f.getDTO());
2493 FolderDTO result = folder.getDTO();
2494 result.setSubfolders(subfolders);
2495 return folder.getDTO();
2499 public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2501 throw new ObjectNotFoundException("No user specified");
2502 if (folderId == null)
2503 throw new ObjectNotFoundException("No folder specified");
2504 User user = dao.getEntityById(User.class, callingUserId);
2505 Folder folder = dao.getEntityById(Folder.class, folderId);
2506 // Check permissions
2507 if (!folder.hasReadPermission(user))
2508 throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2510 FolderDTO result = folder.getDTO();
2511 result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2516 public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2517 throws ObjectNotFoundException, InsufficientPermissionsException {
2519 throw new ObjectNotFoundException("No user specified");
2521 throw new ObjectNotFoundException("No file specified");
2523 throw new ObjectNotFoundException("No valid version specified");
2524 User user = dao.getEntityById(User.class, userId);
2525 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2526 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2527 throw new InsufficientPermissionsException("You don't have the necessary permissions");
2528 FileBody body = dao.getFileVersion(fileId, version);
2529 return body.getDTO();
2533 public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2535 throw new ObjectNotFoundException("No user specified");
2536 User user = dao.getEntityById(User.class, userId);
2537 user.setAcceptedPolicy(isAccepted);
2542 public void updateAccounting(User user, Date date, long bandwidthDiff) {
2543 dao.updateAccounting(user, date, bandwidthDiff);
2547 public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2549 throw new ObjectNotFoundException("No user specified");
2550 if (folderId == null)
2551 throw new ObjectNotFoundException("No folder specified");
2552 User user = dao.getEntityById(User.class, userId);
2553 Folder folder = dao.getEntityById(Folder.class, folderId);
2554 // Check permissions
2555 if (!folder.hasReadPermission(user))
2561 * Reset WebDAV password for given user.
2564 * @return the new password
2565 * @throws ObjectNotFoundException
2568 public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2570 throw new ObjectNotFoundException("No user specified");
2571 User user = dao.getEntityById(User.class, userId);
2572 user.generateWebDAVPassword();
2573 return user.getWebDAVPassword();