X-Git-Url: https://code.grnet.gr/git/pithos/blobdiff_plain/78214787f3d70d7b909463ed6fe666ac8f9b7049..c4a1323760135e13d4a41e4bc80371056919f510:/src/gr/ebs/gss/server/ejb/ExternalAPIBean.java diff --git a/src/gr/ebs/gss/server/ejb/ExternalAPIBean.java b/src/gr/ebs/gss/server/ejb/ExternalAPIBean.java index 94d9c91..88059a0 100644 --- a/src/gr/ebs/gss/server/ejb/ExternalAPIBean.java +++ b/src/gr/ebs/gss/server/ejb/ExternalAPIBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd. + * Copyright 2007, 2008, 2009, 2010 Electronic Business Systems Ltd. * * This file is part of GSS. * @@ -19,9 +19,12 @@ package gr.ebs.gss.server.ejb; import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration; + +import gr.ebs.gss.admin.client.ui.UsersTable; import gr.ebs.gss.client.exceptions.DuplicateNameException; import gr.ebs.gss.client.exceptions.GSSIOException; import gr.ebs.gss.client.exceptions.InsufficientPermissionsException; +import gr.ebs.gss.client.exceptions.InvitationUsedException; import gr.ebs.gss.client.exceptions.ObjectNotFoundException; import gr.ebs.gss.client.exceptions.QuotaExceededException; import gr.ebs.gss.server.domain.AuditInfo; @@ -31,14 +34,14 @@ import gr.ebs.gss.server.domain.FileTag; import gr.ebs.gss.server.domain.FileUploadStatus; import gr.ebs.gss.server.domain.Folder; import gr.ebs.gss.server.domain.Group; +import gr.ebs.gss.server.domain.FileLock; +import gr.ebs.gss.server.domain.Invitation; import gr.ebs.gss.server.domain.Nonce; import gr.ebs.gss.server.domain.Permission; import gr.ebs.gss.server.domain.User; -import gr.ebs.gss.server.domain.dto.FileBodyDTO; -import gr.ebs.gss.server.domain.dto.FileHeaderDTO; -import gr.ebs.gss.server.domain.dto.FolderDTO; -import gr.ebs.gss.server.domain.dto.GroupDTO; -import gr.ebs.gss.server.domain.dto.PermissionDTO; +import gr.ebs.gss.server.domain.UserClass; +import gr.ebs.gss.server.domain.UserLogin; +import gr.ebs.gss.server.domain.WebDavNonce; import gr.ebs.gss.server.domain.dto.StatsDTO; import gr.ebs.gss.server.domain.dto.UserDTO; @@ -48,20 +51,21 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.StringWriter; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Random; import java.util.Set; import java.util.StringTokenizer; import javax.ejb.EJB; import javax.ejb.EJBException; +import javax.ejb.EJBTransactionRolledbackException; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; @@ -73,35 +77,30 @@ import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.QueueConnectionFactory; import javax.jms.Session; -import javax.jws.WebMethod; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpException; -import org.apache.commons.httpclient.NameValuePair; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.StringRequestEntity; +import javax.persistence.PersistenceException; + import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.w3c.dom.DOMException; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer; +import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest; +import org.apache.solr.client.solrj.response.QueryResponse; +import org.apache.solr.common.SolrDocument; +import org.apache.solr.common.SolrDocumentList; +import org.apache.solr.common.SolrException; +import org.apache.solr.common.SolrInputDocument; +import org.hibernate.exception.ConstraintViolationException; + +import com.novell.ldap.LDAPAttribute; +import com.novell.ldap.LDAPAttributeSet; +import com.novell.ldap.LDAPConnection; +import com.novell.ldap.LDAPEntry; +import com.novell.ldap.LDAPException; /** * The concrete implementation of the ExternalAPI interface. @@ -138,20 +137,36 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { */ private static Random random = new Random(); + /** + * Mark the folder and all of its parent folders as modified from the specified user. + */ + private void touchParentFolders(Folder folder, User user, Date date) { + Folder f = folder; + while (f != null) { + AuditInfo ai = f.getAuditInfo(); + ai.setModifiedBy(user); + ai.setModificationDate(date); + f.setAuditInfo(ai); + f = f.getParent(); + } + } + + private Long getRootFolderId(Long userId) throws ObjectNotFoundException { + if (userId == null) + throw new ObjectNotFoundException("No user specified"); + return dao.getRootFolderId(userId); + } + @Override - public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException { + public Folder getRootFolder(Long userId) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); Folder folder = dao.getRootFolder(userId); - return folder.getDTO(); + return folder; } - /* - * (non-Javadoc) - * - * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolder(java.lang.Long) - */ - public FolderDTO getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException { + @Override + public Folder getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (folderId == null) @@ -161,39 +176,31 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { // Check permissions if (!folder.hasReadPermission(user)) throw new InsufficientPermissionsException("You don't have the permissions to read this folder"); - return folder.getDTO(); + return expandFolder(folder); } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getUser(java.lang.Long) - */ + @Override public User getUser(Long userId) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); return dao.getEntityById(User.class, userId); } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserDTO(java.lang.Long) - */ + @Override public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException { return getUser(userId).getDTO(); } - /* - * (non-Javadoc) - * - * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroup(java.lang.Long) - */ - public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException { + @Override + public Group getGroup(final Long groupId) throws ObjectNotFoundException { if (groupId == null) throw new ObjectNotFoundException("No group specified"); final Group group = dao.getEntityById(Group.class, groupId); - return group.getDTO(); + return group; } @Override - public GroupDTO getGroup(Long userId, String name) throws ObjectNotFoundException { + public Group getGroup(Long userId, String name) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (name == null) @@ -202,27 +209,20 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { List groups = user.getGroupsSpecified(); for (Group group: groups) if (group.getName().equals(name)) - return group.getDTO(); + return group; throw new ObjectNotFoundException("Group " + name + " not found"); } - /* - * (non-Javadoc) - * - * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroups(java.lang.Long) - */ - public List getGroups(final Long userId) throws ObjectNotFoundException { + @Override + public List getGroups(final Long userId) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); final List groups = dao.getGroups(userId); - final List result = new ArrayList(); - for (final Group g : groups) - result.add(g.getDTO()); - return result; + return groups; } @Override - public List getFiles(Long userId, Long folderId, boolean ignoreDeleted) + public List getFiles(Long userId, Long folderId, boolean ignoreDeleted) throws ObjectNotFoundException, InsufficientPermissionsException { // Validate. if (userId == null) @@ -233,21 +233,12 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { Folder folder = dao.getEntityById(Folder.class, folderId); if (!folder.hasReadPermission(user)) throw new InsufficientPermissionsException("You don't have the permissions to read this folder"); - // Do the actual work. - List result = new ArrayList(); List files = dao.getFiles(folderId, userId, ignoreDeleted); - for (FileHeader f : files) - result.add(f.getDTO()); - return result; + return files; } - /* - * (non-Javadoc) - * - * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsers(java.lang.Long, - * java.lang.Long) - */ - public List getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException { + @Override + public List getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException { // Validate. if (userId == null) throw new ObjectNotFoundException("No user specified"); @@ -256,14 +247,11 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { // Do the actual work. final List users = dao.getUsers(groupId); - final List result = new ArrayList(); - for (final User u : users) - result.add(u.getDTO()); - return result; + return users; } @Override - public void createFolder(Long userId, Long parentId, String name) + public Folder createFolder(Long userId, Long parentId, String name) throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException { // Validate. if (userId == null) @@ -290,7 +278,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { " to write to this folder"); // Do the actual work. - createFolder(name, parent, creator); + return createFolder(name, parent, creator); } /** @@ -299,8 +287,9 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { * @param name * @param parent * @param creator + * @return the new folder */ - private void createFolder(String name, Folder parent, User creator) { + private Folder createFolder(String name, Folder parent, User creator) { Folder folder = new Folder(); folder.setName(name); if (parent != null) { @@ -316,6 +305,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { auditInfo.setModifiedBy(creator); auditInfo.setModificationDate(now); folder.setAuditInfo(auditInfo); + touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate()); if (parent != null) for (Permission p : parent.getPermissions()) { @@ -335,15 +325,15 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { permission.setModifyACL(true); folder.addPermission(permission); } + + if(parent != null) + folder.setReadForAll(parent.isReadForAll()); + dao.create(folder); + return folder; } - /* - * (non-Javadoc) - * - * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFolder(java.lang.Long, - * java.lang.Long) - */ + @Override public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException { // Validate. if (userId == null) @@ -361,12 +351,33 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")"); throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")"); } + removeSubfolderFiles(folder); parent.removeSubfolder(folder); dao.delete(folder); + touchParentFolders(parent, user, new Date()); + } + + /** + * Traverses the folder and deletes all actual files (file system) + * regardless of permissions + * + * @param folder + */ + private void removeSubfolderFiles(Folder folder) { + //remove files for all subfolders + for (Folder subfolder:folder.getSubfolders()) + removeSubfolderFiles(subfolder); + //remove this folder's file bodies (actual files) + for (FileHeader file:folder.getFiles()) { + for (FileBody body:file.getBodies()) + deleteActualFile(body.getStoredFilePath()); + indexFile(file.getId(), true); + } } + @Override @SuppressWarnings("unchecked") - public List getSubfolders(Long userId, Long folderId) + public List getSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException { if (userId == null) throw new ObjectNotFoundException("No user specified"); @@ -376,53 +387,78 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { Folder folder = dao.getEntityById(Folder.class, folderId); if (!folder.hasReadPermission(user)) throw new InsufficientPermissionsException("You don't have the permissions to read this folder"); - List result = new ArrayList(); + List result = new ArrayList(); if (folder.hasReadPermission(user)) for (Folder f : folder.getSubfolders()) if (f.hasReadPermission(user) && !f.isDeleted()) - result.add(f.getDTO()); + result.add(f); return result; } @Override - public void modifyFolder(Long userId, Long folderId, String folderName) - throws InsufficientPermissionsException, ObjectNotFoundException, DuplicateNameException { + public Folder updateFolder(Long userId, Long folderId, String folderName, + Boolean readForAll, + Set permissions) + throws InsufficientPermissionsException, ObjectNotFoundException, + DuplicateNameException { // Validate. if (userId == null) throw new ObjectNotFoundException("No user specified"); if (folderId == null) throw new ObjectNotFoundException("No folder specified"); - if (StringUtils.isEmpty(folderName)) - throw new ObjectNotFoundException("New folder name is empty"); Folder folder = dao.getEntityById(Folder.class, folderId); User user = dao.getEntityById(User.class, userId); - if (!folder.hasWritePermission(user)) + if (folderName != null && !folder.hasWritePermission(user)) + throw new InsufficientPermissionsException("You don't have the necessary permissions"); + if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user)) throw new InsufficientPermissionsException("You don't have the necessary permissions"); + // Check permissions for making file public. + if (readForAll != null && !user.equals(folder.getOwner())) + throw new InsufficientPermissionsException("Only the owner can make a folder public or not public"); Folder parent = folder.getParent(); - if (parent != null) - if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName)) - throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level"); + if (folderName != null) { + if (parent != null) + if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName)) + throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level"); - // Do the actual modification. - folder.setName(folderName); + // Do the actual modification. + folder.setName(folderName); + } + if (permissions != null) + setFolderPermissions(user, folder, permissions); + if (readForAll != null) + setFolderReadForAll(user, folder, readForAll); + folder.getAuditInfo().setModificationDate(new Date()); + folder.getAuditInfo().setModifiedBy(user); dao.update(folder); + touchParentFolders(folder, user, new Date()); + // Re-index the folder contents if it was modified. + if ((permissions != null && !permissions.isEmpty()) || readForAll != null) { + indexFolder(folder); + } + + return folder; } - /* - * (non-Javadoc) - * - * @see gr.ebs.gss.server.ejb.ExternalAPI#createGroup(java.lang.Long, - * java.lang.String) - */ + private void indexFolder(Folder folder) { + for (FileHeader fh : folder.getFiles()) + indexFile(fh.getId(), false); + for (Folder f : folder.getSubfolders()) + indexFolder(f); + } + + @Override public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException { // Validate. if (userId == null) throw new ObjectNotFoundException("No user specified"); if (StringUtils.isEmpty(name)) throw new ObjectNotFoundException("New group name is empty"); + if (name.indexOf('/')>=0) + throw new IllegalArgumentException("Character '/' is not allowed in group name"); if (dao.existsGroup(userId, name)) throw new DuplicateNameException("A group with the name '" + name + "' already exists"); @@ -434,12 +470,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { owner.createGroup(name); } - /* - * (non-Javadoc) - * - * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteGroup(java.lang.Long, - * java.lang.Long) - */ + @Override public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException { // Validate. if (userId == null) @@ -450,17 +481,20 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { // Do the actual work. final User owner = dao.getEntityById(User.class, userId); final Group group = dao.getEntityById(Group.class, groupId); + final Date now = new Date(); // Only delete the group if actually owned by the user. if (group.getOwner().equals(owner)) { List folders = dao.getFoldersPermittedForGroup(userId, groupId); for (Folder f : folders){ f.getPermissions().removeAll(group.getPermissions()); - for(FileHeader file : f.getFiles()) + for(FileHeader file : f.getFiles()){ file.getPermissions().removeAll(group.getPermissions()); + } } - List files = dao.getSharedFilesNotInSharedFolders(userId); - for(FileHeader h : files) + List files = dao.getFilesPermittedForGroup(userId, groupId); + for(FileHeader h : files){ h.getPermissions().removeAll(group.getPermissions()); + } owner.removeSpecifiedGroup(group); dao.delete(group); } @@ -468,7 +502,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { } @Override - public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream) + public FileHeader createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream) throws DuplicateNameException, ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException { File file = null; @@ -478,12 +512,13 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { // Supply a more accurate problem description. throw new GSSIOException("Problem creating file",ioe); } - return createFile(userId, folderId, name, mimeType, file); + return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath()); } /* (non-Javadoc) * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean) */ + @Override public void indexFile(Long fileId, boolean delete) { Connection qConn = null; Session session = null; @@ -549,12 +584,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { return secondFolder + File.separator + filename; } - /* - * (non-Javadoc) - * - * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFile(java.lang.Long, - * java.lang.Long) - */ + @Override public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException { // Validate. if (userId == null) @@ -570,21 +600,23 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { final User user = dao.getEntityById(User.class, userId); if (!file.hasDeletePermission(user)) throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")"); - for (final FileBody body : file.getBodies()) { - final File fileContents = new File(body.getStoredFilePath()); - if (!fileContents.delete()) - logger.error("Could not delete file " + body.getStoredFilePath()); - } + for (final FileBody body : file.getBodies()) + deleteActualFile(body.getStoredFilePath()); dao.delete(file); + touchParentFolders(parent, user, new Date()); indexFile(fileId, true); } - /* - * (non-Javadoc) - * - * @see gr.ebs.gss.server.ejb.ExternalAPI#createTag(java.lang.Long, - * java.lang.Long, java.lang.String) - */ + @Override + public void deleteActualFile(String path) { + if (path == null) + return; + File file = new File(path); + if (!file.delete()) + logger.error("Could not delete file " + path); + } + + @Override public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); @@ -595,34 +627,57 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { final User user = dao.getEntityById(User.class, userId); final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId); + final Folder parent = fh.getFolder(); + if (parent == null) + throw new ObjectNotFoundException("The specified file has no parent folder"); user.addTag(fh, tag); + touchParentFolders(parent, user, new Date()); } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserTags(java.lang.Long) - */ - @WebMethod(operationName = "getUserTags") + @Override public Set getUserTags(final Long userId) throws ObjectNotFoundException { return dao.getUserTags(userId); } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFile(java.lang.Long, java.lang.Long, java.lang.String, java.util.Set) - */ - public void updateFile(Long userId, Long fileId, String name, String tagSet) throws ObjectNotFoundException, InsufficientPermissionsException { + @Override + public void updateFile(Long userId, Long fileId, String name, + String tagSet, Date modificationDate, Boolean versioned, + Boolean readForAll, Set permissions) + throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (fileId == null) throw new ObjectNotFoundException("No file specified"); FileHeader file = dao.getEntityById(FileHeader.class, fileId); - User user = dao.getEntityById(User.class, userId); - if (!file.hasWritePermission(user)) - throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")"); + final Folder parent = file.getFolder(); + if (parent == null) + throw new ObjectNotFoundException("The specified file has no parent folder"); - if (name != null) + User user = dao.getEntityById(User.class, userId); + // Check permissions for modifying the file metadata. + if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user)) + throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")"); + // Check permissions for making file public. + if (readForAll != null && !user.equals(file.getOwner())) + throw new InsufficientPermissionsException("Only the owner can make a file public or not public"); + // Check permissions for modifying the ACL. + if(permissions != null && !permissions.isEmpty() && !file.hasModifyACLPermission(user)) + throw new InsufficientPermissionsException("User " + user.getId() + " cannot update the permissions on file " + file.getName() + "(" + file.getId() + ")"); + + if (name != null) { + // Do plain check for file already exists. + // Extreme concurrency case should be caught by constraint violation later. + if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists"); file.setName(name); - List tags = file.getFileTags(); + } + + if (modificationDate != null) + file.getAuditInfo().setModificationDate(modificationDate); + else + file.getAuditInfo().setModificationDate(new Date()); + file.getAuditInfo().setModifiedBy(user); + List tags = file.getFileTags(); if (tagSet != null) { Iterator i = tags.iterator(); while (i.hasNext()) { @@ -637,9 +692,35 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { while (st.hasMoreTokens()) new FileTag(user, file, st.nextToken().trim()); } + if (versioned != null && !file.isVersioned() == versioned) { + if (file.isVersioned()) + removeOldVersions(userId, fileId); + file.setVersioned(versioned); + } + if (readForAll != null && user.equals(file.getOwner())) + file.setReadForAll(readForAll); + if (permissions != null && !permissions.isEmpty()) + setFilePermissions(file, permissions); + + /* + * Force constraint violation to manifest itself here. + * This should cover extreme concurrency cases that the simple check + * above hasn't caught. + */ + try { + dao.flush(); + } + catch (EJBTransactionRolledbackException e) { + Throwable cause = e.getCause(); + if (cause instanceof PersistenceException && cause.getCause() instanceof ConstraintViolationException) + throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists"); + throw e; + } + + touchParentFolders(parent, user, new Date()); // Re-index the file if it was modified. - if (name != null || tagSet != null) + if (name != null || tagSet != null || (permissions != null && !permissions.isEmpty()) || readForAll != null) indexFile(fileId, false); } @@ -670,6 +751,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { /* (non-Javadoc) * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long) */ + @Override public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException { if (userId == null) throw new ObjectNotFoundException("No user specified"); @@ -695,10 +777,8 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { } } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getFile(java.lang.Long, java.lang.Long) - */ - public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException { + @Override + public FileHeader getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (fileId == null) @@ -707,11 +787,11 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { final FileHeader file = dao.getEntityById(FileHeader.class, fileId); if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user)) throw new InsufficientPermissionsException("You don't have the necessary permissions"); - return file.getDTO(); + return file; } @Override - public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException { + public FileBody getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (fileId == null) @@ -721,7 +801,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user)) throw new InsufficientPermissionsException("You don't have the necessary permissions"); FileBody body = dao.getEntityById(FileBody.class, bodyId); - return body.getDTO(); + return body; } @Override @@ -741,10 +821,12 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { return getRootFolder(owner.getId()); // Store the last element, since it requires special handling. String lastElement = pathElements.remove(pathElements.size() - 1); - FolderDTO cursor = getRootFolder(owner.getId()); + + Folder cursor = null; + Long rootFolderId = getRootFolderId(owner.getId()); // Traverse and verify the specified folder path. for (String pathElement : pathElements) { - cursor = getFolder(cursor.getId(), pathElement); + cursor = getFolder(cursor==null ? rootFolderId : cursor.getId(), pathElement); if (cursor.isDeleted()) throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found"); } @@ -752,14 +834,14 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { // Use the lastElement to retrieve the actual resource. Object resource = null; try { - FileHeaderDTO file = getFile(cursor.getId(), lastElement); + FileHeader file = getFile(cursor==null ? rootFolderId : cursor.getId(), lastElement); if (ignoreDeleted && file.isDeleted()) throw new ObjectNotFoundException("Resource not found"); resource = file; } catch (ObjectNotFoundException e) { // Perhaps the requested resource is not a file, so // check for folders as well. - FolderDTO folder = getFolder(cursor.getId(), lastElement); + Folder folder = getFolder(cursor==null ? rootFolderId : cursor.getId(), lastElement); if (ignoreDeleted && folder.isDeleted()) throw new ObjectNotFoundException("Resource not found"); resource = folder; @@ -771,7 +853,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { * Retrieve a file for the specified user that has the specified name and * its parent folder has id equal to folderId. * - * @param userId the ID of the current user * @param folderId the ID of the parent folder * @param name the name of the requested file * @return the file found @@ -779,14 +860,14 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { * found, with the exception message mentioning the precise * problem */ - private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException { + private FileHeader getFile(Long folderId, String name) throws ObjectNotFoundException { if (folderId == null) throw new ObjectNotFoundException("No parent folder specified"); if (StringUtils.isEmpty(name)) throw new ObjectNotFoundException("No file specified"); FileHeader file = dao.getFile(folderId, name); - return file.getDTO(); + return file; } /** @@ -800,17 +881,17 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { * found, with the exception message mentioning the precise * problem */ - private FolderDTO getFolder(Long parentId, String name) throws ObjectNotFoundException { + private Folder getFolder(Long parentId, String name) throws ObjectNotFoundException { if (parentId == null) throw new ObjectNotFoundException("No parent folder specified"); if (StringUtils.isEmpty(name)) throw new ObjectNotFoundException("No folder specified"); Folder folder = dao.getFolder(parentId, name); - return folder.getDTO(); + return folder; } - private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException { + private FileHeader updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException { File file = null; try { file = uploadFile(resourceInputStream, userId); @@ -818,7 +899,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { // Supply a more accurate problem description. throw new GSSIOException("Problem creating file",ioe); } - return updateFileContents(userId, fileId, mimeType, file); + return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath()); } @Override @@ -831,9 +912,9 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { throw new ObjectNotFoundException("No destination specified"); Object destination = getResourceAtPath(userId, getParentPath(dest), true); - if (!(destination instanceof FolderDTO)) + if (!(destination instanceof Folder)) throw new ObjectNotFoundException("Destination parent folder not found"); - FolderDTO parent = (FolderDTO) destination; + Folder parent = (Folder) destination; copyFile(userId, fileId, parent.getId(), getLastElement(dest)); } @@ -849,9 +930,9 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { throw new ObjectNotFoundException("No destination specified"); Object destination = getResourceAtPath(ownerId, getParentPath(dest), true); - if (!(destination instanceof FolderDTO)) + if (!(destination instanceof Folder)) throw new ObjectNotFoundException("Destination parent folder not found"); - FolderDTO parent = (FolderDTO) destination; + Folder parent = (Folder) destination; copyFile(userId, fileId, parent.getId(), getLastElement(dest)); } @@ -871,6 +952,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { User user = dao.getEntityById(User.class, userId); if (!file.hasReadPermission(user) || !destination.hasWritePermission(user)) throw new InsufficientPermissionsException("You don't have the necessary permissions"); + boolean versioned = file.isVersioned(); int versionsNumber = file.getBodies().size(); FileBody oldestBody = file.getBodies().get(0); assert oldestBody != null; @@ -878,6 +960,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { try { createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents)); FileHeader copiedFile = dao.getFile(destination.getId(), destName); + copiedFile.setVersioned(versioned); dao.flush(); if (versionsNumber > 1) for (int i = 1; i < versionsNumber; i++) { @@ -906,9 +989,9 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { throw new ObjectNotFoundException("No destination specified"); Object destination = getResourceAtPath(userId, getParentPath(dest), true); - if (!(destination instanceof FolderDTO)) + if (!(destination instanceof Folder)) throw new ObjectNotFoundException("Destination folder not found"); - FolderDTO parent = (FolderDTO) destination; + Folder parent = (Folder) destination; copyFolder(userId, folderId, parent.getId(), getLastElement(dest)); } @@ -942,9 +1025,9 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { throw new ObjectNotFoundException("No destination specified"); Object destination = getResourceAtPath(ownerId, getParentPath(dest), true); - if (!(destination instanceof FolderDTO)) + if (!(destination instanceof Folder)) throw new ObjectNotFoundException("Destination folder not found"); - FolderDTO parent = (FolderDTO) destination; + Folder parent = (Folder) destination; copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest)); } @@ -1045,15 +1128,19 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { if (parent == null) throw new ObjectNotFoundException("The specified file has no parent folder"); User user = dao.getEntityById(User.class, userId); - if (!file.hasDeletePermission(user)) - throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")"); - - file.setDeleted(true); - dao.update(file); + trashFile(user, file); + touchParentFolders(parent, user, new Date()); } + private void trashFile(User user, FileHeader file) throws InsufficientPermissionsException { + if (!file.hasDeletePermission(user)) + throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")"); + + file.setDeleted(true); + } + @Override - public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, DuplicateNameException, GSSIOException, QuotaExceededException { + public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (ownerId == null) @@ -1064,14 +1151,14 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { throw new ObjectNotFoundException("No destination specified"); Object destination = getResourceAtPath(ownerId, getParentPath(dest), true); - if (!(destination instanceof FolderDTO)) + if (!(destination instanceof Folder)) throw new ObjectNotFoundException("Destination parent folder not found"); - FolderDTO parent = (FolderDTO) destination; + Folder parent = (Folder) destination; moveFile(userId, fileId, parent.getId(), getLastElement(dest)); } @Override - public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, DuplicateNameException, GSSIOException, QuotaExceededException { + public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (fileId == null) @@ -1082,25 +1169,46 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { throw new ObjectNotFoundException("No destination file name specified"); FileHeader file = dao.getEntityById(FileHeader.class, fileId); + Folder source = file.getFolder(); Folder destination = dao.getEntityById(Folder.class, destId); User owner = dao.getEntityById(User.class, userId); if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner)) throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")"); - FileBody body = file.getCurrentBody(); - assert body != null; - File contents = new File(body.getStoredFilePath()); - try { - createFile(owner.getId(), destination.getId(), destName, body.getMimeType(), new FileInputStream(contents)); - } catch (FileNotFoundException e) { - throw new ObjectNotFoundException("File contents not found for file " + body.getStoredFilePath()); - } - deleteFile(userId, fileId); + // if the destination folder belongs to another user: + if (!file.getOwner().equals(destination.getOwner())) { + // (a) check if the destination quota allows the move + if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize()) + throw new QuotaExceededException("Not enough free space available"); + User newOwner = destination.getOwner(); + // (b) if quota OK, change the owner of the file + file.setOwner(newOwner); + // if the file has no permission for the new owner, add it + Permission ownerPermission = null; + for (final Permission p : file.getPermissions()) + if (p.getUser() != null) + if (p.getUser().equals(newOwner)) { + ownerPermission = p; + break; + } + if (ownerPermission == null) { + ownerPermission = new Permission(); + ownerPermission.setUser(newOwner); + file.addPermission(ownerPermission); + } + ownerPermission.setRead(true); + ownerPermission.setWrite(true); + ownerPermission.setModifyACL(true); + } + // move the file to the destination folder + file.setFolder(destination); + touchParentFolders(source, owner, new Date()); + touchParentFolders(destination, owner, new Date()); } @Override - public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException { + public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (ownerId == null) @@ -1111,34 +1219,77 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { throw new ObjectNotFoundException("No destination specified"); Object destination = getResourceAtPath(ownerId, getParentPath(dest), true); - if (!(destination instanceof FolderDTO)) + if (!(destination instanceof Folder)) throw new ObjectNotFoundException("Destination parent folder not found"); - FolderDTO parent = (FolderDTO) destination; + Folder parent = (Folder) destination; moveFolder(userId, folderId, parent.getId(), getLastElement(dest)); } @Override - public void moveFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException { - // TODO Simple Move and delete of original folder, in production - // scenario we must first check individual files and folders permissions - copyFolderStructure(userId, folderId, destId, destName); - deleteFolder(userId, folderId); + public void moveFolder(Long userId, Long folderId, Long destId, String destName) + throws ObjectNotFoundException, InsufficientPermissionsException, + QuotaExceededException { + Folder source = dao.getEntityById(Folder.class, folderId); + Folder destination = dao.getEntityById(Folder.class, destId); + User user = dao.getEntityById(User.class, userId); + User sourceOwner = source.getOwner(); + User destinationOwner = destination.getOwner(); + // Do not move trashed folders and contents. + if (source.isDeleted()) + return; + // Check permissions. + if (!destination.hasWritePermission(user) + || !source.hasReadPermission(user) + || !source.hasWritePermission(user)) + throw new InsufficientPermissionsException("You don't have the " + + "necessary permissions"); + // Use the same timestamp for all subsequent modifications to make + // changes appear simultaneous. + Date now = new Date(); + // If source and destination are not in the same user's namespace, + // change owners and check quota. + if (!sourceOwner.equals(destinationOwner)) { + changeOwner(source, destinationOwner, user, now); + if (getQuotaLeft(destinationOwner.getId()) < 0) + throw new QuotaExceededException("Not enough free space " + + "available in destination folder"); + } + // Perform the move. + Folder oldParent = source.getParent(); + oldParent.removeSubfolder(source); + destination.addSubfolder(source); + // Mark the former parent and destination trees upwards as modified. + touchParentFolders(oldParent, user, now); + touchParentFolders(source, user, now); } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getDeletedFiles(java.lang.Long) + /** + * Recursively change the owner of the specified folder and all of its + * contents to the specified owner. Also mark them all as modified with the + * specified modifier and modificationDate. */ - public List getDeletedFiles(Long userId) throws ObjectNotFoundException { + private void changeOwner(Folder folder, User owner, User modifier, Date modificationDate) { + for (FileHeader file: folder.getFiles()) { + file.setOwner(owner); + file.getAuditInfo().setModificationDate(modificationDate); + file.getAuditInfo().setModifiedBy(modifier); + } + for (Folder sub: folder.getSubfolders()) + changeOwner(sub, owner, modifier, modificationDate); + folder.setOwner(owner); + folder.getAuditInfo().setModificationDate(modificationDate); + folder.getAuditInfo().setModifiedBy(modifier); + } + + @Override + public List getDeletedFiles(Long userId) throws ObjectNotFoundException { // Validate. if (userId == null) throw new ObjectNotFoundException("No user specified"); // Do the actual work. - final List result = new ArrayList(); final List files = dao.getDeletedFiles(userId); - for (final FileHeader f : files) - result.add(f.getDTO()); - return result; + return files; } @Override @@ -1155,32 +1306,39 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { if (parent == null) throw new ObjectNotFoundException("The specified file has no parent folder"); User user = dao.getEntityById(User.class, userId); - if (!file.hasDeletePermission(user)) - throw new InsufficientPermissionsException("User " + user.getUsername() + - " cannot restore file " + file.getName()); - - file.setDeleted(false); - dao.update(file); + untrashFile(user, file); + touchParentFolders(parent, user, new Date()); } + private void untrashFile(User user, FileHeader file) throws InsufficientPermissionsException { + if (!file.hasDeletePermission(user)) + throw new InsufficientPermissionsException("User " + user.getUsername() + + " cannot restore file " + file.getName()); + + file.setDeleted(false); + } + @Override public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException { - if (userId == null) - throw new ObjectNotFoundException("No user specified"); - if (folderId == null) - throw new ObjectNotFoundException("No folder specified"); - Folder folder = dao.getEntityById(Folder.class, folderId); - User user = dao.getEntityById(User.class, userId); - if (!folder.hasDeletePermission(user)) - throw new InsufficientPermissionsException("You don't have the necessary permissions"); - folder.setDeleted(true); - dao.update(folder); - for (FileHeader file : folder.getFiles()) - moveFileToTrash(userId, file.getId()); - for (Folder subFolder : folder.getSubfolders()) - moveFolderToTrash(userId, subFolder.getId()); - - } + if (userId == null) + throw new ObjectNotFoundException("No user specified"); + if (folderId == null) + throw new ObjectNotFoundException("No folder specified"); + Folder folder = dao.getEntityById(Folder.class, folderId); + User user = dao.getEntityById(User.class, userId); + trashFolder(user, folder); + touchParentFolders(folder, user, new Date()); + } + + private void trashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException { + if (!folder.hasDeletePermission(user)) + throw new InsufficientPermissionsException("You don't have the necessary permissions"); + folder.setDeleted(true); + for (FileHeader file : folder.getFiles()) + trashFile(user, file); + for (Folder subFolder : folder.getSubfolders()) + trashFolder(user, subFolder); + } @Override public void removeFolderFromTrash(Long userId, Long folderId) @@ -1191,48 +1349,50 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { throw new ObjectNotFoundException("No folder specified"); Folder folder = dao.getEntityById(Folder.class, folderId); User user = dao.getEntityById(User.class, userId); - if (!folder.hasDeletePermission(user)) - throw new InsufficientPermissionsException("User " + user.getUsername() + - " cannot restore folder " + folder.getName()); - folder.setDeleted(false); - for (FileHeader file : folder.getFiles()) - removeFileFromTrash(userId, file.getId()); - for (Folder subFolder : folder.getSubfolders()) - removeFolderFromTrash(userId, subFolder.getId()); - dao.update(folder); + untrashFolder(user, folder); + touchParentFolders(folder, user, new Date()); } + private void untrashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException { + if (!folder.hasDeletePermission(user)) + throw new InsufficientPermissionsException("User " + user.getUsername() + + " cannot restore folder " + folder.getName()); + folder.setDeleted(false); + for (FileHeader file : folder.getFiles()) + untrashFile(user, file); + for (Folder subFolder : folder.getSubfolders()) + untrashFolder(user, subFolder); + } + @Override - public List getDeletedRootFolders(Long userId) throws ObjectNotFoundException { + public List getDeletedRootFolders(Long userId) throws ObjectNotFoundException { List folders = dao.getDeletedRootFolders(userId); - List result = new ArrayList(); - for (Folder folder : folders) - result.add(folder.getDTO()); - return result; + return folders; } @Override public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException { - List deletedRootFolders = getDeletedRootFolders(userId); - for (FolderDTO fdto : deletedRootFolders) - deleteFolder(userId, fdto.getId()); - List deletedFiles = getDeletedFiles(userId); - for (FileHeaderDTO filedto : deletedFiles) - deleteFile(userId, filedto.getId()); + List deletedRootFolders = getDeletedRootFolders(userId); + for (Folder folder : deletedRootFolders) + deleteFolder(userId, folder.getId()); + List deletedFiles = getDeletedFiles(userId); + for (FileHeader file : deletedFiles) + deleteFile(userId, file.getId()); } @Override public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException { - List deletedRootFolders = getDeletedRootFolders(userId); - for (FolderDTO fdto : deletedRootFolders) - removeFolderFromTrash(userId, fdto.getId()); - List deletedFiles = getDeletedFiles(userId); - for (FileHeaderDTO filedto : deletedFiles) - removeFileFromTrash(userId, filedto.getId()); + List deletedRootFolders = getDeletedRootFolders(userId); + for (Folder folder : deletedRootFolders) + removeFolderFromTrash(userId, folder.getId()); + List deletedFiles = getDeletedFiles(userId); + for (FileHeader file : deletedFiles) + removeFileFromTrash(userId, file.getId()); } @Override - public User createUser(String username, String name, String mail) throws ObjectNotFoundException { + public User createUser(String username, String name, String mail, + String idp, String idpid) throws ObjectNotFoundException { if (username == null) throw new ObjectNotFoundException("No username specified"); if (name == null) @@ -1242,12 +1402,17 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { user.setUsername(username); user.setName(name); user.setEmail(mail); + user.setIdentityProvider(idp); + user.setIdentityProviderId(idpid); Date now = new Date(); AuditInfo auditInfo = new AuditInfo(); auditInfo.setCreationDate(now); auditInfo.setModificationDate(now); user.setAuditInfo(auditInfo); + user.setActive(true); user.generateAuthToken(); + user.generateWebDAVPassword(); + user.setUserClass(getDefaultUserClass()); dao.create(user); // Make sure we get an ID in the user object. dao.flush(); @@ -1256,6 +1421,29 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { return user; } + /** + * Get the default user class, which is the one with the lowest quota. + */ + private UserClass getDefaultUserClass() { + return getUserClasses().get(0); + } + + @Override + public List getUserClasses() { + List classes = dao.getUserClasses(); + // Create a default user class for first-time use. Afterwards, the + // admin should modify or add to the userclass table. + if (classes.size() == 0) { + UserClass defaultClass = new UserClass(); + defaultClass.setName("default"); + Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L)); + defaultClass.setQuota(defaultQuota); + dao.create(defaultClass); + classes.add(defaultClass); + } + return classes; + } + @Override public User findUserByEmail(String email) { return dao.findUserByEmail(email); @@ -1267,17 +1455,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { } @Override - public User updateUser(String username, String name, String mail) throws ObjectNotFoundException { - if (username == null) - throw new ObjectNotFoundException("No username specified"); - - User user = dao.getUser(username); - user.setName(name); - user.setEmail(mail); - return user; - } - - @Override public User findUser(String username) { if (username == null) return null; @@ -1293,11 +1470,8 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { return user; } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolderPermissions(java.lang.Long, java.lang.Long) - */ @Override - public Set getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException { + public Set getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (folderId == null) @@ -1307,56 +1481,72 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { if(!folder.hasReadPermission(user)) throw new InsufficientPermissionsException("You don't have the necessary permissions"); Set perms = folder.getPermissions(); - Set result = new LinkedHashSet(); + Set result = new LinkedHashSet(); for (Permission perm : perms) if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) - result.add(perm.getDTO()); + result.add(perm); for (Permission perm : perms) if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) { } else - result.add(perm.getDTO()); + result.add(perm); return result; } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#setFolderPermissions(java.lang.Long, java.lang.Long, java.util.Set) + /** + * Set the provided permissions as the new permissions of the specified + * folder. + * + * @param user + * @param folder + * @param permissions + * @throws ObjectNotFoundException + * @throws InsufficientPermissionsException */ - @Override - public void setFolderPermissions(Long userId, Long folderId, Set permissions) throws ObjectNotFoundException, InsufficientPermissionsException { - if (userId == null) - throw new ObjectNotFoundException("No user specified"); - if (folderId == null) - throw new ObjectNotFoundException("No folder specified"); - User user = dao.getEntityById(User.class, userId); - Folder folder = dao.getEntityById(Folder.class, folderId); - if(!folder.hasModifyACLPermission(user)) - throw new InsufficientPermissionsException("You don't have the necessary permissions"); - folder.getPermissions().clear(); - for (PermissionDTO dto : permissions) { - if (dto.getUser()!=null && dto.getUser().getId().equals(folder.getOwner().getId()) && (!dto.hasRead() || !dto.hasWrite() || !dto.hasModifyACL())) - throw new InsufficientPermissionsException("Can't remove permissions from owner"); - folder.addPermission(getPermission(dto)); + private void setFolderPermissions(User user, Folder folder, Set permissions) throws ObjectNotFoundException, InsufficientPermissionsException { + if (permissions != null && !permissions.isEmpty()) { + User owner = folder.getOwner(); + Permission ownerPerm = null; + for (Permission perm : permissions) + if (perm.getUser() != null && perm.getUser().getId().equals(owner.getId())) { + ownerPerm = perm; + break; + } + if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL()) + throw new InsufficientPermissionsException("Can't remove permissions from owner"); + // Delete previous entries + for (Permission perm: folder.getPermissions()) + dao.delete(perm); + folder.getPermissions().clear(); + for (Permission p : permissions) { + // Skip 'empty' permission entries. + if (!p.getRead() && !p.getWrite() && !p.getModifyACL()) continue; + folder.addPermission(getPermission(p)); + } + dao.update(folder); + for (FileHeader file : folder.getFiles()) { + setFilePermissions(file, permissions); + Date now = new Date(); + file.getAuditInfo().setModificationDate(now); + file.getAuditInfo().setModifiedBy(user); + } + for (Folder sub : folder.getSubfolders()) + setFolderPermissions(user, sub, permissions); } - dao.update(folder); - for (FileHeader fh : folder.getFiles()) - setFilePermissions(userId, fh.getId(), fh.isReadForAll(), permissions); - for (Folder sub : folder.getSubfolders()) - setFolderPermissions(userId, sub.getId(), permissions); } - private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException { + private Permission getPermission(Permission perm) throws ObjectNotFoundException { Permission res = new Permission(); - if (dto.getGroup() != null) - res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId())); - else if (dto.getUser() != null) - if (dto.getUser().getId() == null) - res.setUser(dao.getUser(dto.getUser().getUsername())); + if (perm.getGroup() != null) + res.setGroup(dao.getEntityById(Group.class, perm.getGroup().getId())); + else if (perm.getUser() != null) + if (perm.getUser().getId() == null) + res.setUser(dao.getUser(perm.getUser().getUsername())); else - res.setUser(dao.getEntityById(User.class, dto.getUser().getId())); - res.setRead(dto.hasRead()); - res.setWrite(dto.hasWrite()); - res.setModifyACL(dto.hasModifyACL()); + res.setUser(dao.getEntityById(User.class, perm.getUser().getId())); + res.setRead(perm.hasRead()); + res.setWrite(perm.hasWrite()); + res.setModifyACL(perm.hasModifyACL()); return res; } @@ -1364,18 +1554,12 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String) */ @Override - public List getUsersByUserNameLike(String username) { + public List getUsersByUserNameLike(String username) { List users = dao.getUsersByUserNameLike(username); - List result = new ArrayList(); - for (User u : users) - result.add(u.getDTO()); - return result; + return users; } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#addUserToGroup(java.lang.Long, java.lang.Long, java.lang.Long) - */ @Override public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException { if (userId == null) @@ -1406,22 +1590,19 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { } @Override - public List getSharedRootFolders(Long userId) throws ObjectNotFoundException { + public List getSharedRootFolders(Long userId) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); List folders = dao.getSharedRootFolders(userId); - List result = new ArrayList(); + List result = new ArrayList(); for (Folder f : folders) { - FolderDTO dto = f.getDTO(); - dto.setSubfolders(getSharedSubfolders(userId, f.getId())); - result.add(dto); + Folder lf = f; + lf.setSubfolders(getSharedSubfolders(userId, f.getId())); + result.add(lf); } return result; } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#removeMemberFromGroup(java.lang.Long, java.lang.Long, java.lang.Long) - */ @Override public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException { if (userId == null) @@ -1440,27 +1621,21 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersSharingFoldersForUser(java.lang.Long) - */ @Override - public List getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException { + public List getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException { List users = dao.getUsersSharingFoldersForUser(userId); List usersFiles = dao.getUsersSharingFilesForUser(userId); - List res = new ArrayList(); + List result = new ArrayList(); for (User u : users) - res.add(u.getDTO()); + result.add(u); for(User fu : usersFiles) if(!users.contains(fu)) - res.add(fu.getDTO()); - return res; + result.add(fu); + return result; } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getFilePermissions(java.lang.Long, java.lang.Long) - */ @Override - public Set getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException { + public Set getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (fileId == null) @@ -1470,134 +1645,121 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { if(!folder.hasReadPermission(user)) throw new InsufficientPermissionsException("You don't have the necessary permissions"); Set perms = folder.getPermissions(); - Set result = new LinkedHashSet(); + Set result = new LinkedHashSet(); for (Permission perm : perms) if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) - result.add(perm.getDTO()); + result.add(perm); for (Permission perm : perms) if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) { } else - result.add(perm.getDTO()); + result.add(perm); return result; } - @Override - public void setFilePermissions(Long userId, Long fileId, Boolean readForAll, Set permissions) throws ObjectNotFoundException, InsufficientPermissionsException { - if (userId == null) - throw new ObjectNotFoundException("No user specified"); - if (fileId == null) - throw new ObjectNotFoundException("No folder specified"); - - User user = dao.getEntityById(User.class, userId); - FileHeader file = dao.getEntityById(FileHeader.class, fileId); - if(!file.hasModifyACLPermission(user)) - throw new InsufficientPermissionsException("You don't have the necessary permissions"); - - if (readForAll != null) - if (user.equals(file.getOwner())) - file.setReadForAll(readForAll); - else - throw new InsufficientPermissionsException("Only the owner can change the read-for-all flag"); - + /** + * Set the provided permissions as the new permissions of the specified + * file. This method sets the modification date/user attributes to the + * current values as a side effect. + * + * @param file + * @param permissions + * @throws ObjectNotFoundException + * @throws InsufficientPermissionsException + */ + private void setFilePermissions(FileHeader file, + Set permissions) + throws ObjectNotFoundException, InsufficientPermissionsException { if (permissions != null && !permissions.isEmpty()) { + Permission ownerPerm = null; + for (Permission perm : permissions) + if (perm.getUser() != null && perm.getUser().getId().equals(file.getOwner().getId())) { + ownerPerm = perm; + break; + } + if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL()) + throw new InsufficientPermissionsException("Can't remove permissions from owner"); + // Delete previous entries. + for (Permission perm: file.getPermissions()) + dao.delete(perm); file.getPermissions().clear(); - for (PermissionDTO dto : permissions) { - if (dto.getUser()!=null && dto.getUser().getId().equals(file.getOwner().getId()) && (!dto.hasRead() || !dto.hasWrite() || !dto.hasModifyACL())) - throw new InsufficientPermissionsException("Can't remove permissions from owner"); - file.addPermission(getPermission(dto)); + for (Permission perm : permissions) { + // Skip 'empty' permission entries. + if (!perm.getRead() && !perm.getWrite() && !perm.getModifyACL()) continue; + file.addPermission(getPermission(perm)); } + dao.flush(); } - - // Update the file if there was a change. - if (readForAll != null || permissions != null && !permissions.isEmpty()) - dao.update(file); - } @Override - public List getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException { + public List getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); List files = dao.getSharedFilesNotInSharedFolders(userId); - List result = new ArrayList(); - for (FileHeader f : files) - result.add(f.getDTO()); - return result; + return files; } @Override - public List getSharedFiles(Long userId) throws ObjectNotFoundException { + public List getSharedFiles(Long userId) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); List files = dao.getSharedFiles(userId); - List result = new ArrayList(); - for (FileHeader f : files) - result.add(f.getDTO()); - return result; + return files; } @Override - public List getSharedFolders(Long userId) throws ObjectNotFoundException { + public List getSharedFolders(Long userId) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); List folders = dao.getSharedFolders(userId); - List result = new ArrayList(); - for (Folder f : folders) - result.add(f.getDTO()); - return result; + return folders; } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getSharedFiles(java.lang.Long, java.lang.Long) - */ @Override - public List getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException { + public List getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException { if (ownerId == null) throw new ObjectNotFoundException("No owner specified"); if (callingUserId == null) throw new ObjectNotFoundException("No calling user specified"); List folders = dao.getSharedFiles(ownerId, callingUserId); - List result = new ArrayList(); - for (FileHeader f : folders) - result.add(f.getDTO()); - return result; + return folders; } @Override - public List getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException { + public List getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException { if (ownerId == null) throw new ObjectNotFoundException("No owner specified"); if (callingUserId == null) throw new ObjectNotFoundException("No calling user specified"); List folders = dao.getSharedRootFolders(ownerId, callingUserId); - List result = new ArrayList(); + List result = new ArrayList(); for (Folder f : folders) { - FolderDTO dto = f.getDTO(); - dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId())); - result.add(dto); + Folder lf = f; + lf.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId())); + result.add(lf); } return result; } @Override - public List getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException { + public List getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (folderId == null) throw new ObjectNotFoundException("No folder specified"); User user = dao.getEntityById(User.class, userId); Folder folder = dao.getEntityById(Folder.class, folderId); - List result = new ArrayList(); - if (folder.isShared(user)) + List result = new ArrayList(); + if (folder.isShared(user) || folder.isReadForAll()) for (Folder f : folder.getSubfolders()) - if (f.isShared(user) && !f.isDeleted()) - result.add(f.getDTO()); + if ((f.isShared(user) || f.isReadForAll()) && !f.isDeleted()) + result.add(f); return result; } @Override - public List getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException { + public List getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (callingUserId == null) @@ -1606,127 +1768,96 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { throw new ObjectNotFoundException("No folder specified"); User user = dao.getEntityById(User.class, callingUserId); Folder folder = dao.getEntityById(Folder.class, folderId); - List result = new ArrayList(); + List result = new ArrayList(); if (folder.isSharedForOtherUser(user)) for (Folder f : folder.getSubfolders()) if (f.isSharedForOtherUser(user) && !f.isDeleted()){ - FolderDTO dto = f.getDTO(); - dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId())); - result.add(dto); + Folder lf = f; + lf.setSubfolders(getSharedSubfolders(userId, callingUserId, lf.getId())); + result.add(lf); } return result; } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#searchFiles(java.lang.Long, java.lang.String) - */ @Override - public List searchFiles(Long userId, String query) throws ObjectNotFoundException { + public List searchFiles(Long userId, String query) throws ObjectNotFoundException { + long startTime = System.currentTimeMillis(); if (userId == null) throw new ObjectNotFoundException("No user specified"); User user = getUser(userId); if (query == null) throw new ObjectNotFoundException("No query specified"); List files = search(user.getId(), query); - List res = new ArrayList(); - for(FileHeader f : files) - res.add(f.getDTO()); - return res; + + long stopTime = System.currentTimeMillis(); + logger.info("Total time: " + (stopTime - startTime)); + return files; } /** * Performs the actuals search on the solr server and returns the results * - * We have to use the dismax query type (instead of the - * standard) because it allows for search time field boosting. This is because we can't use indexing - * time field boosting due to the patched rich indexing API that does not allow it - * * @param userId * @param query * @return a List of FileHeader objects */ private List search(Long userId, String query) { + final int maxRows = 100; + List result = new ArrayList(); try { - HttpClient httpClient = new HttpClient(); - - GetMethod method = new GetMethod(getConfiguration().getString("solrSelectUrl")); - NameValuePair[] params = {new NameValuePair("qt", "dismax"), - new NameValuePair("q", query), - new NameValuePair("sort", "score desc"), - new NameValuePair("indent", "on")}; - method.setQueryString(params); - int retryCount = 0; - int statusCode = 0; - String response = null; - do { - statusCode = httpClient.executeMethod(method); - logger.debug("HTTP status: " + statusCode); - response = method.getResponseBodyAsString(); - logger.debug(response); - retryCount++; - if (statusCode != 200 && retryCount < 3) - try { - Thread.sleep(3000); //Give Solr a little time to be available - } catch (InterruptedException e) { - } - } while (statusCode != 200 && retryCount < 3); - if (statusCode != 200) - throw new EJBException("Search query return error:\n" + response); - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.parse(method.getResponseBodyAsStream()); - method.releaseConnection(); - - Node root = doc.getElementsByTagName("response").item(0); - Node lst = root.getFirstChild().getNextSibling(); - Node status = lst.getFirstChild().getNextSibling(); - if (status.getAttributes().getNamedItem("name").getNodeValue().equals("status") && - status.getTextContent().equals("0")) { - List fileResult = new ArrayList(); - Node result = lst.getNextSibling().getNextSibling(); - NodeList docs = result.getChildNodes(); - User user = getUser(userId); - for (int i=1; i groups = dao.getGroupsContainingUser(userId); + String constructedQuery = escapeCharacters(normalizeSearchQuery(query)) + " AND (public: true OR ureaders: " + userId; + if (!groups.isEmpty()) { + constructedQuery += " OR ("; + for (int i=0; i maxRows) { + solrQuery.setRows(Integer.valueOf((int) results.getNumFound())); + response = solr.query(solrQuery); + results = response.getResults(); + } + long stopTime = System.currentTimeMillis(); + logger.info("Search time:" + (stopTime - startTime)); + User user = getUser(userId); + startTime = System.currentTimeMillis(); + for (SolrDocument d : results) { + Long id = Long.valueOf((String) d.getFieldValue("id")); + try { + FileHeader f = dao.getEntityById(FileHeader.class, id); + result.add(f); + } catch (ObjectNotFoundException e) { + logger.warn("Search result id " + id + " cannot be found", e); } - return fileResult; } - throw new EJBException(); - } catch (HttpException e) { - throw new EJBException(e); - } catch (IOException e) { - throw new EJBException(e); - } catch (SAXException e) { + stopTime = System.currentTimeMillis(); + logger.info("File loads: " + (stopTime - startTime)); + } catch (MalformedURLException e) { + logger.error(e); throw new EJBException(e); - } catch (ParserConfigurationException e) { + } catch (SolrServerException e) { + logger.error(e); throw new EJBException(e); } catch (ObjectNotFoundException e) { + logger.error(e); throw new EJBException(e); } + return result; } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#copyFiles(java.lang.Long, java.util.List, java.lang.Long) - */ @Override public void copyFiles(Long userId, List fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException { for(Long l : fileIds){ @@ -1737,11 +1868,8 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFiles(java.lang.Long, java.util.List, java.lang.Long) - */ @Override - public void moveFiles(Long userId, List fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, DuplicateNameException, GSSIOException, QuotaExceededException { + public void moveFiles(Long userId, List fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException { for(Long l : fileIds){ FileHeader file = dao.getEntityById(FileHeader.class, l); moveFile(userId, l, destId, file.getName()); @@ -1749,60 +1877,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFiles(java.lang.Long, java.util.List) - */ - @Override - public void deleteFiles(Long userId, List fileIds) throws ObjectNotFoundException, InsufficientPermissionsException { - if (userId == null) - throw new ObjectNotFoundException("No user specified"); - final User user = dao.getEntityById(User.class, userId); - List filesToRemove = new ArrayList(); - //first delete database objects - for(Long fileId : fileIds){ - if (fileId == null) - throw new ObjectNotFoundException("No file specified"); - final FileHeader file = dao.getEntityById(FileHeader.class, fileId); - final Folder parent = file.getFolder(); - if (parent == null) - throw new ObjectNotFoundException("The specified file has no parent folder"); - if (!file.hasDeletePermission(user)) - throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")"); - - parent.removeFile(file); - for (final FileBody body : file.getBodies()) { - final File fileContents = new File(body.getStoredFilePath()); - filesToRemove.add(fileContents); - } - dao.delete(file); - } - //then remove physical files if everything is ok - for(File physicalFile : filesToRemove) - if (!physicalFile.delete()) - logger.error("Could not delete file " + physicalFile.getPath()); - //then unindex deleted files - for(Long fileId : fileIds) - indexFile(fileId, true); - - } - - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFilesToTrash(java.lang.Long, java.util.List) - */ - @Override - public void moveFilesToTrash(Long userId, List fileIds) throws ObjectNotFoundException, InsufficientPermissionsException { - for(Long l : fileIds) - moveFileToTrash(userId, l); - - } - - @Override - public void removeFilesFromTrash(Long userId, List fileIds) throws ObjectNotFoundException, InsufficientPermissionsException { - for(Long l : fileIds) - removeFileFromTrash(userId, l); - - } - @Override public Nonce createNonce(Long userId) throws ObjectNotFoundException { if (userId == null) @@ -1839,9 +1913,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { user.setNonceExpiryDate(nonceExpiryDate); } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserStatistics(java.lang.Long) - */ @Override public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException { if (userId == null) @@ -1856,57 +1927,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { return stats; } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#getVersions(java.lang.Long, java.lang.Long) - */ - @Override - public List getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException { - if (userId == null) - throw new ObjectNotFoundException("No user specified"); - if (fileId == null) - throw new ObjectNotFoundException("No file specified"); - User user = dao.getEntityById(User.class, userId); - FileHeader header = dao.getEntityById(FileHeader.class, fileId); - if(!header.hasReadPermission(user)) - throw new InsufficientPermissionsException("You don't have the necessary permissions"); - List result = new LinkedList(); - for(int i = header.getBodies().size()-1 ; i>=0; i--) - result.add(header.getBodies().get(i).getDTO()); - return result; - } - - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#removeVersion(java.lang.Long, java.lang.Long, java.lang.Long) - */ - @Override - public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException { - if (userId == null) - throw new ObjectNotFoundException("No user specified"); - if (fileId == null) - throw new ObjectNotFoundException("No file specified"); - if (bodyId == null) - throw new ObjectNotFoundException("No body specified"); - User user = dao.getEntityById(User.class, userId); - FileHeader header = dao.getEntityById(FileHeader.class, fileId); - if(!header.hasWritePermission(user)) - throw new InsufficientPermissionsException("You don't have the necessary permissions"); - FileBody body = dao.getEntityById(FileBody.class, bodyId); - if(body.equals(header.getCurrentBody())){ - - if(header.getBodies().size() == 1) - throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!"); - for(FileBody b : header.getBodies()) - if(b.getVersion() == body.getVersion()-1) - header.setCurrentBody(b); - } - final File fileContents = new File(body.getStoredFilePath()); - if (!fileContents.delete()) - logger.error("Could not delete file " + body.getStoredFilePath()); - header.getBodies().remove(body); - - - } - @Override public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException, GSSIOException, QuotaExceededException { if (userId == null) @@ -1945,190 +1965,97 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { while(it.hasNext()){ FileBody body = it.next(); if(!body.equals(header.getCurrentBody())){ - final File fileContents = new File(body.getStoredFilePath()); - if (!fileContents.delete()) - logger.error("Could not delete file " + body.getStoredFilePath()); + deleteActualFile(body.getStoredFilePath()); it.remove(); dao.delete(body); } } header.getCurrentBody().setVersion(1); - } - - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#toggleFileVersioning(java.lang.Long, java.lang.Long, boolean) - */ - @Override - public void toggleFileVersioning(Long userId, Long fileId, boolean versioned) throws ObjectNotFoundException, InsufficientPermissionsException { - if (userId == null) - throw new ObjectNotFoundException("No user specified"); - if (fileId == null) - throw new ObjectNotFoundException("No file specified"); - User user = dao.getEntityById(User.class, userId); - FileHeader header = dao.getEntityById(FileHeader.class, fileId); - if(!header.hasWritePermission(user)) - throw new InsufficientPermissionsException("You don't have the necessary permissions"); - if(!header.isVersioned() == versioned){ - if(header.isVersioned()) - removeOldVersions(userId, fileId); - header.setVersioned(versioned); - - } + Folder parent = header.getFolder(); + touchParentFolders(parent, user, new Date()); } /** - * Gets the quota left for specified userId - * @param userId - * @return + * Gets the quota left for specified user ID. */ - private Long getQuotaLeft(Long userId){ + private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{ Long fileSize = dao.getFileSize(userId); Long quota = getQuota(userId); return quota - fileSize; } /** - * Gets the quota for specified userId - * @param userId - * @return + * Gets the quota for specified user ID. */ - private Long getQuota(@SuppressWarnings("unused") Long userId){ - Long quota = getConfiguration().getLong("quota", new Long(52428800L)); - return quota; + private Long getQuota(Long userId) throws ObjectNotFoundException{ + UserClass uc = getUser(userId).getUserClass(); + if (uc == null) + uc = getDefaultUserClass(); + return uc.getQuota(); } - public void rebuildSolrIndex() { - MessageProducer sender = null; - Session session = null; - Connection qConn = null; + @Override + @TransactionAttribute(TransactionAttributeType.NEVER) + public String rebuildSolrIndex() { try { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - Document doc = db.newDocument(); - Node root = doc.createElement("delete"); - doc.appendChild(root); - Node queryNode = doc.createElement("query"); - root.appendChild(queryNode); - queryNode.appendChild(doc.createTextNode("*:*")); - - TransformerFactory fact = TransformerFactory.newInstance(); - Transformer trans = fact.newTransformer(); - trans.setOutputProperty(OutputKeys.INDENT, "yes"); - StringWriter sw = new StringWriter(); - StreamResult sr = new StreamResult(sw); - DOMSource source = new DOMSource(doc); - trans.transform(source, sr); - logger.debug(sw.toString()); - - HttpClient httpClient = new HttpClient(); - PostMethod method = new PostMethod(getConfiguration().getString("solrUpdateUrl")); - method.setRequestEntity(new StringRequestEntity(sw.toString())); - int retryCount = 0; - int statusCode = 0; - String response = null; - do { - statusCode = httpClient.executeMethod(method); - logger.debug("HTTP status: " + statusCode); - response = method.getResponseBodyAsString(); - logger.debug(response); - retryCount++; - if (statusCode != 200 && retryCount < 3) - try { - Thread.sleep(10000); //Give Solr a little time to be available - } catch (InterruptedException e) { - } - } while (statusCode != 200 && retryCount < 3); - method.releaseConnection(); - if (statusCode != 200) - throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response); - List fileIds = dao.getAllFileIds(); - - Context jndiCtx = new InitialContext(); - ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA"); - Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue"); - qConn = factory.createConnection(); - session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE); - sender = session.createProducer(queue); + CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url")); + solr.deleteByQuery("*:*"); + solr.commit(); + logger.info("Deleted everything in solr"); + List fileIds = dao.getAllFileIds(); + logger.info("Total of " + fileIds.size() + " will be indexed"); + int i = 0; for (Long id : fileIds) { - MapMessage map = session.createMapMessage(); - map.setObject("id", id); - map.setBoolean("delete", false); - sender.send(map); + postFileToSolr(solr, id); + i++; + if (i % 10 == 0) { + solr.commit(); + logger.info("Sent commit to solr at file " + i); + } } - sendOptimize(httpClient, 0); - } catch (DOMException e) { - throw new EJBException(e); - } catch (TransformerConfigurationException e) { - throw new EJBException(e); - } catch (IllegalArgumentException e) { - throw new EJBException(e); - } catch (HttpException e) { - throw new EJBException(e); - } catch (UnsupportedEncodingException e) { - throw new EJBException(e); - } catch (ParserConfigurationException e) { - throw new EJBException(e); - } catch (TransformerException e) { - throw new EJBException(e); + solr.optimize(); + solr.commit(); + logger.info("Finished indexing of " + i + " files"); + return "Finished indexing of " + i + " files"; } catch (IOException e) { throw new EJBException(e); - } catch (NamingException e) { - throw new EJBException(e); - } catch (JMSException e) { + } catch (SolrServerException e) { throw new EJBException(e); } - finally { - try { - if (sender != null) - sender.close(); - if (session != null) - session.close(); - if (qConn != null) - qConn.close(); - } - catch (JMSException e) { - logger.warn(e); - } - } } - /** - * Sends a optimize message to the solr server - * - * @param httpClient - * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive - * calls to stop the recursion - * @throws UnsupportedEncodingException - * @throws IOException - * @throws HttpException - */ - private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException { - PostMethod method = null; + @Override + @TransactionAttribute(TransactionAttributeType.NEVER) + public String refreshSolrIndex() { try { - logger.debug("Optimize retry: " + retryCount); - method = new PostMethod(getConfiguration().getString("solrUpdateUrl")); - method.setRequestEntity(new StringRequestEntity("", "text/xml", "iso8859-1")); - int statusCode = httpClient.executeMethod(method); - logger.debug("HTTP status: " + statusCode); - String response = method.getResponseBodyAsString(); - logger.debug(response); - if (statusCode != 200 && retryCount < 2) { - try { - Thread.sleep(10000); //Give Solr a little time to be available - } catch (InterruptedException e) { - } - sendOptimize(httpClient, retryCount + 1); + CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url")); + + List fileIds = dao.getAllFileIds(); + logger.info("Total of " + fileIds.size() + " will be indexed"); + int i = 0; + for (Long id : fileIds) { + postFileToSolr(solr, id); + i++; } - } - finally { - if (method != null) - method.releaseConnection(); + if (i % 10 == 0) { + solr.commit(); + logger.info("Sent commit to solr at file " + i); + } + solr.optimize(); + solr.commit(); + logger.info("Finished indexing of " + i + " files"); + return "Finished indexing of " + i + " files"; + } catch (IOException e) { + throw new EJBException(e); + } catch (SolrServerException e) { + throw new EJBException(e); } } - public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, File fileObject) + @Override + public FileHeader createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath) throws DuplicateNameException, ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException { // Validate. @@ -2161,6 +2088,8 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { parent.addFile(file); // set file owner to folder owner file.setOwner(parent.getOwner()); + //set file's readForAll value according to parent folder readForAll value + file.setReadForAll(parent.isReadForAll()); final Date now = new Date(); final AuditInfo auditInfo = new AuditInfo(); @@ -2184,20 +2113,19 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { // Create the file body. try { - createFileBody(name, contentType, fileObject, file, auditInfo, owner); + createFileBody(name, contentType, fileSize, filePath, file, auditInfo); } catch (FileNotFoundException e) { throw new GSSIOException(e); } + touchParentFolders(parent, owner, new Date()); dao.flush(); indexFile(file.getId(), false); - return file.getDTO(); + return file; } - /* (non-Javadoc) - * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFileContents(java.lang.Long, java.lang.Long, java.lang.String, java.io.InputStream) - */ - public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, File fileObject) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException { + @Override + public FileHeader updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException { if (userId == null) throw new ObjectNotFoundException("No user specified"); if (fileId == null) @@ -2222,13 +2150,15 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { auditInfo.setModifiedBy(owner); auditInfo.setModificationDate(now); try { - createFileBody(file.getName(), contentType, fileObject, file, auditInfo, owner); + createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo); } catch (FileNotFoundException e) { throw new GSSIOException(e); } + Folder parent = file.getFolder(); + touchParentFolders(parent, owner, new Date()); indexFile(fileId, false); - return file.getDTO(); + return file; } /** @@ -2239,7 +2169,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { */ private String identifyMimeType(String filename) { if (filename.indexOf('.') != -1) { - String extension = filename.substring(filename.lastIndexOf('.')); + String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH); if (".doc".equals(extension)) return "application/msword"; else if (".xls".equals(extension)) @@ -2248,6 +2178,16 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { return "application/vnd.ms-powerpoint"; else if (".pdf".equals(extension)) return "application/pdf"; + else if (".gif".equals(extension)) + return "image/gif"; + else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension)) + return "image/jpeg"; + else if (".tiff".equals(extension) || ".tif".equals(extension)) + return "image/tiff"; + else if (".png".equals(extension)) + return "image/png"; + else if (".bmp".equals(extension)) + return "image/bmp"; } // when all else fails assign the default mime type return DEFAULT_MIME_TYPE; @@ -2259,23 +2199,25 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { * * @param name the original file name * @param mimeType the content type - * @param uploadedFile the uploaded file contents + * @param fileSize the uploaded file size + * @param filePath the uploaded file full path * @param header the file header that will be associated with the new body * @param auditInfo the audit info - * @param owner the owner of the file * @throws FileNotFoundException * @throws QuotaExceededException + * @throws ObjectNotFoundException if the owner was not found */ - private void createFileBody(String name, String mimeType, File uploadedFile, - FileHeader header, AuditInfo auditInfo, User owner) - throws FileNotFoundException, QuotaExceededException { + private void createFileBody(String name, String mimeType, long fileSize, String filePath, + FileHeader header, AuditInfo auditInfo) + throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException { long currentTotalSize = 0; if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null) currentTotalSize = header.getTotalSize(); Long quotaLeft = getQuotaLeft(header.getOwner().getId()); - if(quotaLeft < uploadedFile.length()-currentTotalSize) { - uploadedFile.delete(); + if(quotaLeft < fileSize-currentTotalSize) { + // quota exceeded -> delete the file + deleteActualFile(filePath); throw new QuotaExceededException("Not enough free space available"); } @@ -2289,9 +2231,9 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { else body.setMimeType(mimeType); body.setAuditInfo(auditInfo); - body.setFileSize(uploadedFile.length()); + body.setFileSize(fileSize); body.setOriginalFilename(name); - body.setStoredFilePath(uploadedFile.getAbsolutePath()); + body.setStoredFilePath(filePath); //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED if(!header.isVersioned() && header.getCurrentBody() != null){ header.setCurrentBody(null); @@ -2299,9 +2241,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { Iterator it = header.getBodies().iterator(); while(it.hasNext()){ FileBody bo = it.next(); - File fileContents = new File(bo.getStoredFilePath()); - if (!fileContents.delete()) - logger.error("Could not delete file " + bo.getStoredFilePath()); + deleteActualFile(bo.getStoredFilePath()); it.remove(); dao.delete(bo); } @@ -2310,11 +2250,13 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { dao.flush(); header.addBody(body); + header.setAuditInfo(auditInfo); dao.create(body); } + @Override @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException { if (userId == null) @@ -2348,6 +2290,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { } + @Override public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{ if (userId == null) @@ -2370,6 +2313,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { } + @Override public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{ if (userId == null) throw new ObjectNotFoundException("No user specified"); @@ -2384,45 +2328,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { } @Override - public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException { - if (userId == null) - throw new ObjectNotFoundException("No user specified"); - if (folderId == null) - throw new ObjectNotFoundException("No folder specified"); - final User user = dao.getEntityById(User.class, userId); - final Folder folder = dao.getEntityById(Folder.class, folderId); - // Check permissions - if (!folder.hasReadPermission(user)) - throw new InsufficientPermissionsException("You don't have the permissions to read this folder"); - List subfolders = new ArrayList(); - if (folder.hasReadPermission(user)) - for (Folder f : folder.getSubfolders()) - if (f.hasReadPermission(user) && !f.isDeleted()) - subfolders.add(f.getDTO()); - FolderDTO result = folder.getDTO(); - result.setSubfolders(subfolders); - return folder.getDTO(); - } - - @Override - public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException { - if (userId == null) - throw new ObjectNotFoundException("No user specified"); - if (folderId == null) - throw new ObjectNotFoundException("No folder specified"); - User user = dao.getEntityById(User.class, callingUserId); - Folder folder = dao.getEntityById(Folder.class, folderId); - // Check permissions - if (!folder.hasReadPermission(user)) - throw new InsufficientPermissionsException("You don't have the permissions to read this folder"); - - FolderDTO result = folder.getDTO(); - result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId())); - return result; - } - - @Override - public FileBodyDTO getFileVersion(Long userId, Long fileId, int version) + public FileBody getFileVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException { if (userId == null) throw new ObjectNotFoundException("No user specified"); @@ -2435,7 +2341,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user)) throw new InsufficientPermissionsException("You don't have the necessary permissions"); FileBody body = dao.getFileVersion(fileId, version); - return body.getDTO(); + return body; } @Override @@ -2466,4 +2372,421 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote { return true; } + @Override + public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException { + if (userId == null) + throw new ObjectNotFoundException("No user specified"); + User user = dao.getEntityById(User.class, userId); + user.generateWebDAVPassword(); + return user.getWebDAVPassword(); + } + + @Override + public Invitation findInvite(String code) { + if (code == null) + return null; + return dao.findInvite(code); + } + + @Override + public void createLdapUser(String username, String firstname, String lastname, String email, String password) { + LDAPConnection lc = new LDAPConnection(); + LDAPAttributeSet attributeSet = new LDAPAttributeSet(); + attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass"))); + attributeSet.add(new LDAPAttribute("uid", username)); + attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname})); + attributeSet.add(new LDAPAttribute("sn", lastname)); + attributeSet.add(new LDAPAttribute("givenName", firstname)); + attributeSet.add(new LDAPAttribute("mail", email)); + attributeSet.add(new LDAPAttribute("userPassword", password)); + String dn = "uid=" + username + "," + getConfiguration().getString("baseDn"); + LDAPEntry newEntry = new LDAPEntry(dn, attributeSet); + try { + lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT); + lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"), + getConfiguration().getString("bindPassword").getBytes("UTF8")); + lc.add(newEntry); + logger.info("Successfully added LDAP account: " + dn); + lc.disconnect(); + } catch(LDAPException e) { + throw new RuntimeException(e); + } catch(UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + + } + + @Override + public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException { + User user = findUser(username); + if (user == null) + throw new ObjectNotFoundException("The user was not found"); + Invitation invite = findInvite(code); + if (invite.getUser() != null) + throw new InvitationUsedException("This code has already been used"); + invite.setUser(user); + UserClass couponClass = getCouponUserClass(); + user.setUserClass(couponClass); + return couponClass; + } + + @Override + public UserClass getCouponUserClass() { + return dao.findCouponUserClass(); + } + + /** + * Set the provided readForAll as the new readforAll value of the specified + * folder and sub-folders. + * + * @param user + * @param folder + * @param readForAll + * @throws ObjectNotFoundException + * + */ + private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){ + if (readForAll != null && user.equals(folder.getOwner())){ + folder.setReadForAll(readForAll); + dao.update(folder); + for (FileHeader file : folder.getFiles()) + file.setReadForAll(readForAll); + if(readForAll) + //only update subfolders when readforall is true. otherwise all sub-folders stay untouched + for (Folder sub : folder.getSubfolders()) + setFolderReadForAll(user, sub, readForAll); + + } + + } + + /** + * Update the userLogin with the values from the supplied object. + */ + + public void addUserLogin(UserLogin userLogin) { + dao.update(userLogin); + + } + + /** + * Retrieves the current session user login and the user's last login + * + * @param userId + * @return a list of last two user logins + * @throws ObjectNotFoundException + */ + + public List getLastUserLogins(Long userId) throws ObjectNotFoundException{ + List userLoginResults = new ArrayList(); + userLoginResults = dao.getLoginsForUser(userId); + if(userLoginResults.size() == 0) + throw new ObjectNotFoundException("No userlogin found for the user"); + //if the user logins for the first time lastLoginDate = currentLoginDate + if(userLoginResults.size()==1) + userLoginResults.add(userLoginResults.get(0)); + return userLoginResults; + } + + + @Override + public void postFileToSolr(CommonsHttpSolrServer solr, Long id) { + try { + FileHeader file = dao.getFileForIndexing(id); + FileBody body = file.getCurrentBody(); + String mime = body.getMimeType(); + boolean multipart = true; + if (!mime.equals("application/pdf") + && !mime.equals("text/plain") + && !mime.equals("text/html") + && !mime.endsWith("msword") + && !mime.endsWith("ms-excel") + && !mime.endsWith("powerpoint") + || (body.getFileSize() > getConfiguration().getLong("solrDocumentUploadLimitInKB") * 1024)) + multipart = false; + + if (!multipart) + sendMetaDataOnly(solr, file); + else { + ContentStreamUpdateRequest solrRequest = new ContentStreamUpdateRequest(getConfiguration().getString("solr.rich.update.path")); + solrRequest.setParam("literal.id", file.getId().toString()); + solrRequest.setParam("literal.name", file.getName()); + for (FileTag t : file.getFileTags()) { + solrRequest.getParams().add("literal.tag", t.getTag()); + } + for (Permission p : file.getPermissions()) { + if (p.getRead()) { + if (p.getUser() != null) + solrRequest.getParams().add("literal.ureaders", p.getUser().getId().toString()); + else if (p.getGroup() != null) + solrRequest.getParams().add("literal.greaders", p.getGroup().getId().toString()); + } + } + solrRequest.setParam("literal.owner", file.getOwner().getId().toString()); + solrRequest.setParam("literal.public", String.valueOf(file.isReadForAll())); + File fsFile = new File(body.getStoredFilePath()); + solrRequest.addFile(fsFile); + try { + solr.request(solrRequest); + } + catch (SolrException e) { + logger.warn("File " + id + " failed with SolrException: " + e.getLocalizedMessage() + ". Retrying without the file"); + //Let 's try without the file + sendMetaDataOnly(solr, file); + } + catch (NullPointerException e) { + logger.warn("File " + id + " failed with NullPointerException: " + e.getLocalizedMessage() + ". Retrying without the file"); + //Let 's try without the file + sendMetaDataOnly(solr, file); + } + catch (SolrServerException e) { + logger.warn("File " + id + " failed with SolrServerException: " + e.getLocalizedMessage() + ". Retrying without the file"); + //Let 's try without the file + sendMetaDataOnly(solr, file); + } + } + } catch (MalformedURLException e) { + throw new EJBException(e); + } catch (ObjectNotFoundException e) { + logger.error("Indexing of file id " + id + " failed.", e); + } catch (SolrServerException e) { + throw new EJBException(e); + } catch (IOException e) { + throw new EJBException(e); + } + } + + private void sendMetaDataOnly(CommonsHttpSolrServer solr, FileHeader file) throws SolrServerException, IOException { + SolrInputDocument solrDoc = new SolrInputDocument(); + solrDoc.addField("id", file.getId().toString()); + solrDoc.addField("name", file.getName()); + for (FileTag t : file.getFileTags()) { + solrDoc.addField("tag", t.getTag()); + } + for (Permission p : file.getPermissions()) { + if (p.getRead()) { + if (p.getUser() != null) + solrDoc.addField("ureaders", p.getUser().getId()); + else if (p.getGroup() != null) + solrDoc.addField("greaders", p.getGroup().getId()); + } + } + solrDoc.addField("owner", file.getOwner().getId()); + solrDoc.addField("public", file.isReadForAll()); + solr.add(solrDoc); + } + + private String tokenizeFilename(String filename){ + StringBuffer result = new StringBuffer(); + StringTokenizer tokenizer = new StringTokenizer(filename,"._"); + while(tokenizer.hasMoreTokens()){ + result.append(tokenizer.nextToken()); + result.append(" "); + } + result.append(filename); + return result.toString(); + } + + private String normalizeSearchQuery(String query) { + if (query.contains("*")) + return query.toLowerCase().replace('ά', 'α').replace('έ', 'ε').replace('ί', 'ι').replace('ή', 'η').replace('ύ', 'υ') + .replace('ό', 'ο').replace('ς', 'σ').replace('ώ', 'ω').replace('ϊ', 'ι').replace('ϋ', 'υ'); + else + return query; + } + + private String escapeCharacters(String text) { + return text.replaceAll(":", "\\\\:"); + } + + /*** NEW METHODS IN ORDER TO AVOID LAZY loading exception in json render + ****/ + @Override + public Folder expandFolder(Folder folder) throws ObjectNotFoundException{ + Folder result = dao.getEntityById(Folder.class, folder.getId()); + result.getSubfolders().size(); + result.getFiles().size(); + result.getPermissions().size(); + return result; +} + + @Override + public FileHeader expandFile(FileHeader folder) throws ObjectNotFoundException{ + FileHeader result = dao.getEntityById(FileHeader.class, folder.getId()); + result.getFolder(); + result.getPermissions().size(); + result.getFileTags().size(); + return result; + } + + @Override + public Group expandGroup(Group folder) throws ObjectNotFoundException{ + Group result = dao.getEntityById(Group.class, folder.getId()); + result.getMembers().size(); + return result; + } + + /* (non-Javadoc) + * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String) + */ + @Override + public User getUserByUserName(String username) { + User result = dao.getUserByUserName(username); + return result; + } + + /*WEBDAV CREATE EMPTY FILE*/ + @Override + public FileHeader createEmptyFile(Long userId, Long folderId, String name) + throws DuplicateNameException, ObjectNotFoundException, GSSIOException, + InsufficientPermissionsException, QuotaExceededException { + // Validate. + if (userId == null) + throw new ObjectNotFoundException("No user specified"); + if (folderId == null) + throw new ObjectNotFoundException("No folder specified"); + String contentType = DEFAULT_MIME_TYPE; + if (StringUtils.isEmpty(name)) + throw new ObjectNotFoundException("No file name specified"); + if (dao.existsFolderOrFile(folderId, name)) + throw new DuplicateNameException("A folder or file with the name '" + name + + "' already exists at this level"); + + // Do the actual work. + Folder parent = null; + try { + parent = dao.getEntityById(Folder.class, folderId); + } catch (final ObjectNotFoundException onfe) { + // Supply a more accurate problem description. + throw new ObjectNotFoundException("Parent folder not found"); + } + final User owner = dao.getEntityById(User.class, userId); + if (!parent.hasWritePermission(owner)) + throw new InsufficientPermissionsException("You don't have the permissions to write to this folder"); + final FileHeader file = new FileHeader(); + file.setName(name); + parent.addFile(file); + // set file owner to folder owner + file.setOwner(parent.getOwner()); + //set file's readForAll value according to parent folder readForAll value + file.setReadForAll(parent.isReadForAll()); + + final Date now = new Date(); + final AuditInfo auditInfo = new AuditInfo(); + auditInfo.setCreatedBy(owner); + auditInfo.setCreationDate(now); + auditInfo.setModifiedBy(owner); + auditInfo.setModificationDate(now); + file.setAuditInfo(auditInfo); + // TODO set the proper versioning flag on creation + file.setVersioned(false); + + for (final Permission p : parent.getPermissions()) { + final Permission permission = new Permission(); + permission.setGroup(p.getGroup()); + permission.setUser(p.getUser()); + permission.setRead(p.getRead()); + permission.setWrite(p.getWrite()); + permission.setModifyACL(p.getModifyACL()); + file.addPermission(permission); + } + // Create the file body. + try { + createEmptyFileBody(name, contentType, 0, file, auditInfo); + } catch (FileNotFoundException e) { + throw new GSSIOException(e); + } + touchParentFolders(parent, owner, new Date()); + dao.flush(); + return file; + } + + private void createEmptyFileBody(String name, String mimeType, long fileSize, + FileHeader header, AuditInfo auditInfo) + throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException { + + long currentTotalSize = 0; + if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null) + currentTotalSize = header.getTotalSize(); + Long quotaLeft = getQuotaLeft(header.getOwner().getId()); + + + FileBody body = new FileBody(); + + // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension + if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType) + || "application/download".equals(mimeType) || "application/force-download".equals(mimeType) + || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType)) + body.setMimeType(identifyMimeType(name)); + else + body.setMimeType(mimeType); + body.setAuditInfo(auditInfo); + body.setFileSize(fileSize); + body.setOriginalFilename(name); + body.setStoredFilePath(generateRepositoryFilePath()); + //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED + if(!header.isVersioned() && header.getCurrentBody() != null){ + header.setCurrentBody(null); + if (header.getBodies() != null) { + Iterator it = header.getBodies().iterator(); + while(it.hasNext()){ + FileBody bo = it.next(); + deleteActualFile(bo.getStoredFilePath()); + it.remove(); + dao.delete(bo); + } + } + } + + dao.flush(); + header.addBody(body); + header.setAuditInfo(auditInfo); + + dao.create(body); + } + /*** WEBDAV LOCK **/ + @Override + public FileLock getLockById(String id) { + return dao.getLockById(id); + } + + @Override + public FileLock getLockByToken(String tokenId) { + return dao.getLockByToken(tokenId); + } + + @Override + public void removeLock(FileLock lock) { + dao.removeLock(lock); + } + + @Override + public FileLock saveOrUpdateLock(FileLock lock) { + return dao.saveOrUpdateLock(lock); + } + + @Override + public WebDavNonce getWebDavNonce(String tokenId) { + return dao.getWebDavNonce(tokenId); + } + + @Override + public void removeWebDavNonce(WebDavNonce nonce) { + dao.removeWebDavNonce(nonce); + } + + @Override + public WebDavNonce saveOrUpdateWebDavNonce(WebDavNonce nonce) { + return dao.saveOrUpdateWebDavNonce(nonce); + } + + /* (non-Javadoc) + * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String) + */ + @Override + public UserDTO getUserByUserName(String username) { + User result = dao.getUserByUserName(username); + return result.getDTO(); + } + }