import javax.ejb.EJB;
import javax.ejb.EJBException;
+import javax.ejb.EJBTransactionRolledbackException;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
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.persistence.PersistenceException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.hibernate.exception.ConstraintViolationException;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
*/
private static Random random = new Random();
+ private void touchParentFolders(Folder folder, User modifiedBy, Date modificationDate) {
+ Folder f = folder;
+ while (f!=null) {
+ AuditInfo ai = f.getAuditInfo();
+ ai.setModifiedBy(modifiedBy);
+ ai.setModificationDate(modificationDate);
+ f.setAuditInfo(ai);
+ f = f.getParent();
+ }
+ }
+
@Override
public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
if (userId == null)
auditInfo.setModifiedBy(creator);
auditInfo.setModificationDate(now);
folder.setAuditInfo(auditInfo);
+ touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
if (parent != null)
for (Permission p : parent.getPermissions()) {
removeSubfolderFiles(folder);
parent.removeSubfolder(folder);
dao.delete(folder);
+ touchParentFolders(parent, user, new Date());
}
/**
}
@Override
- public FolderDTO modifyFolder(Long userId, Long folderId, String folderName)
- throws InsufficientPermissionsException, ObjectNotFoundException, DuplicateNameException {
+ public FolderDTO updateFolder(Long userId, Long folderId, String folderName,
+ Set<PermissionDTO> 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");
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);
+
+ folder.getAuditInfo().setModificationDate(new Date());
+ folder.getAuditInfo().setModifiedBy(user);
dao.update(folder);
+ touchParentFolders(folder, user, new Date());
return folder.getDTO();
}
for (final FileBody body : file.getBodies())
deleteActualFile(body.getStoredFilePath());
dao.delete(file);
+ touchParentFolders(parent, user, new Date());
indexFile(fileId, true);
}
logger.error("Could not delete file " + filePath);
}
- /*
- * (non-Javadoc)
- *
- * @see gr.ebs.gss.server.ejb.ExternalAPI#createTag(java.lang.Long,
- * java.lang.Long, java.lang.String)
- */
public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
if (userId == null)
throw new ObjectNotFoundException("No user specified");
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")
public Set<String> 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 {
+ public void updateFile(Long userId, Long fileId, String name,
+ String tagSet, Date modificationDate, Boolean versioned,
+ Boolean readForAll, Set<PermissionDTO> 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);
+ final Folder parent = file.getFolder();
+ if (parent == null)
+ throw new ObjectNotFoundException("The specified file has no parent folder");
+
User user = dao.getEntityById(User.class, userId);
- if (!file.hasWritePermission(user))
- throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
+ // 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<FileTag> tags = file.getFileTags();
+ if (modificationDate != null)
+ file.getAuditInfo().setModificationDate(modificationDate);
+ else
+ file.getAuditInfo().setModificationDate(new Date());
+ file.getAuditInfo().setModifiedBy(user);
+
+ List<FileTag> tags = file.getFileTags();
if (tagSet != null) {
Iterator<FileTag> i = tags.iterator();
while (i.hasNext()) {
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)
file.setDeleted(true);
dao.update(file);
+ touchParentFolders(parent, user, new Date());
}
@Override
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);
}
// move the file to the destination folder
file.setFolder(destination);
+ touchParentFolders(source, owner, new Date());
+ touchParentFolders(destination, owner, new Date());
}
@Override
file.setDeleted(false);
dao.update(file);
+ touchParentFolders(parent, user, new Date());
}
@Override
throw new InsufficientPermissionsException("You don't have the necessary permissions");
folder.setDeleted(true);
dao.update(folder);
+ touchParentFolders(folder, user, new Date());
for (FileHeader file : folder.getFiles())
moveFileToTrash(userId, file.getId());
for (Folder subFolder : folder.getSubfolders())
for (Folder subFolder : folder.getSubfolders())
removeFolderFromTrash(userId, subFolder.getId());
dao.update(folder);
+ touchParentFolders(folder, user, new Date());
}
@Override
}
- /* (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<PermissionDTO> 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");
+ private void setFolderPermissions(User user, Folder folder, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
// Delete previous entries
for (Permission perm: folder.getPermissions())
dao.delete(perm);
folder.addPermission(getPermission(dto));
}
dao.update(folder);
- for (FileHeader fh : folder.getFiles())
- setFilePermissions(userId, fh.getId(), fh.isReadForAll(), permissions);
+ 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(userId, sub.getId(), permissions);
+ setFolderPermissions(user, sub, permissions);
}
private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
}
- /* (non-Javadoc)
- * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersSharingFoldersForUser(java.lang.Long)
- */
@Override
public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
List<User> users = dao.getUsersSharingFoldersForUser(userId);
return res;
}
- /* (non-Javadoc)
- * @see gr.ebs.gss.server.ejb.ExternalAPI#getFilePermissions(java.lang.Long, java.lang.Long)
- */
@Override
public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
if (userId == null)
return result;
}
- @Override
- public void setFilePermissions(Long userId, Long fileId, Boolean readForAll, Set<PermissionDTO> 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");
-
- // Update the file if there was a change.
- if (readForAll != null || permissions != null && !permissions.isEmpty()) {
- if (permissions != null && !permissions.isEmpty()) {
- // 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");
- // Don't include 'empty' permission
- if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
- file.addPermission(getPermission(dto));
- }
+ /**
+ * 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<PermissionDTO> permissions)
+ throws ObjectNotFoundException, InsufficientPermissionsException {
+ if (permissions != null && !permissions.isEmpty()) {
+ // 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");
+ // Don't include 'empty' permission.
+ if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
+ file.addPermission(getPermission(dto));
}
-
- dao.update(file);
+ dao.flush();
}
}
for (final FileBody body : file.getBodies())
filesToRemove.add(body.getStoredFilePath());
dao.delete(file);
+ touchParentFolders(parent, user, new Date());
}
//then remove physical files if everything is ok
for(String physicalFileName : filesToRemove)
deleteActualFile(body.getStoredFilePath());
header.getBodies().remove(body);
+ Folder parent = header.getFolder();
+ touchParentFolders(parent, user, new Date());
}
}
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());
}
/**
} catch (FileNotFoundException e) {
throw new GSSIOException(e);
}
+ touchParentFolders(parent, owner, new Date());
dao.flush();
indexFile(file.getId(), false);
} catch (FileNotFoundException e) {
throw new GSSIOException(e);
}
+ Folder parent = file.getFolder();
+ touchParentFolders(parent, owner, new Date());
indexFile(fileId, false);
return file.getDTO();
dao.flush();
header.addBody(body);
+ header.setAuditInfo(auditInfo);
dao.create(body);
}