Index rebuild is done synchronously. Added some logging messages for monitoring
[pithos] / src / gr / ebs / gss / server / ejb / ExternalAPIBean.java
index 0cb2971..6014525 100644 (file)
@@ -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.
  *
@@ -22,6 +22,7 @@ import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfigu
 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;
@@ -35,6 +36,7 @@ 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.UserClass;
 import gr.ebs.gss.server.domain.dto.FileBodyDTO;
 import gr.ebs.gss.server.domain.dto.FileHeaderDTO;
 import gr.ebs.gss.server.domain.dto.FolderDTO;
@@ -49,8 +51,8 @@ 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;
@@ -80,32 +82,20 @@ 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 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 org.apache.commons.lang.StringUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+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 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 com.novell.ldap.LDAPAttribute;
 import com.novell.ldap.LDAPAttributeSet;
@@ -184,27 +174,19 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                return folder.getDTO();
        }
 
-       /* (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)
-        */
+       @Override
        public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
                if (groupId == null)
                        throw new ObjectNotFoundException("No group specified");
@@ -226,11 +208,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                throw new ObjectNotFoundException("Group " + name + " not found");
        }
 
-       /*
-        * (non-Javadoc)
-        *
-        * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroups(java.lang.Long)
-        */
+       @Override
        public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
                if (userId == null)
                        throw new ObjectNotFoundException("No user specified");
@@ -261,12 +239,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                return result;
        }
 
-       /*
-        * (non-Javadoc)
-        *
-        * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsers(java.lang.Long,
-        *      java.lang.Long)
-        */
+       @Override
        public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
                // Validate.
                if (userId == null)
@@ -357,17 +330,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.getDTO();
        }
 
-       /*
-        * Deletes the given folder and all its subfolders and files
-        * Only the permissions for top folder are checked
-        *
-        * @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)
@@ -409,6 +380,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                }
        }
 
+       @Override
        @SuppressWarnings("unchecked")
        public List<FolderDTO> getSubfolders(Long userId, Long folderId)
                        throws ObjectNotFoundException, InsufficientPermissionsException {
@@ -430,6 +402,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
 
        @Override
        public FolderDTO updateFolder(Long userId, Long folderId, String folderName,
+                               Boolean readForAll,
                                Set<PermissionDTO> permissions)
                        throws InsufficientPermissionsException, ObjectNotFoundException,
                        DuplicateNameException {
@@ -446,6 +419,9 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                        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 (folderName != null) {
@@ -458,7 +434,8 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                }
                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);
@@ -466,12 +443,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                return folder.getDTO();
        }
 
-       /*
-        * (non-Javadoc)
-        *
-        * @see gr.ebs.gss.server.ejb.ExternalAPI#createGroup(java.lang.Long,
-        *      java.lang.String)
-        */
+       @Override
        public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
                // Validate.
                if (userId == null)
@@ -491,12 +463,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)
@@ -507,17 +474,23 @@ 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<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
                        for (Folder f : folders){
                                f.getPermissions().removeAll(group.getPermissions());
-                               for(FileHeader file : f.getFiles())
+                               touchFolder(f, owner, now);
+                               for(FileHeader file : f.getFiles()){
                                        file.getPermissions().removeAll(group.getPermissions());
+                                       touchFile(file, owner, now);
+                               }
                        }
-                       List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
-                       for(FileHeader h : files)
+                       List<FileHeader> files = dao.getFilesPermittedForGroup(userId, groupId);
+                       for(FileHeader h : files){
                                h.getPermissions().removeAll(group.getPermissions());
+                               touchFile(h, owner, now);
+                       }
                        owner.removeSpecifiedGroup(group);
                        dao.delete(group);
                }
@@ -541,6 +514,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
        /* (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;
@@ -606,12 +580,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)
@@ -634,14 +603,16 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                indexFile(fileId, true);
        }
 
-       private void deleteActualFile(String filePath) {
-               if (filePath == null)
+       @Override
+       public void deleteActualFile(String path) {
+               if (path == null)
                        return;
-               File file = new File(filePath);
+               File file = new File(path);
                if (!file.delete())
-                       logger.error("Could not delete file " + filePath);
+                       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");
@@ -659,10 +630,12 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                touchParentFolders(parent, user, new Date());
        }
 
+       @Override
        public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
                return dao.getUserTags(userId);
        }
 
+       @Override
        public void updateFile(Long userId, Long fileId, String name,
                                String tagSet, Date modificationDate, Boolean versioned,
                                Boolean readForAll,     Set<PermissionDTO> permissions)
@@ -774,6 +747,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");
@@ -799,9 +773,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                }
        }
 
-       /* (non-Javadoc)
-        * @see gr.ebs.gss.server.ejb.ExternalAPI#getFile(java.lang.Long, java.lang.Long)
-        */
+       @Override
        public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
                if (userId == null)
                        throw new ObjectNotFoundException("No user specified");
@@ -875,7 +847,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
@@ -1427,8 +1398,10 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                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();
@@ -1437,6 +1410,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<UserClass> getUserClasses() {
+               List<UserClass> 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);
@@ -1463,9 +1459,6 @@ 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<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
                if (userId == null)
@@ -1500,26 +1493,35 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
         * @throws InsufficientPermissionsException
         */
        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.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");
-                       // Don't include 'empty' permission
-                       if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
-                       folder.addPermission(getPermission(dto));
-               }
-               dao.update(folder);
-               for (FileHeader file : folder.getFiles()) {
-                       setFilePermissions(file, permissions);
-                       Date now = new Date();
-                       file.getAuditInfo().setModificationDate(now);
-                       file.getAuditInfo().setModifiedBy(user);
+               if (permissions != null && !permissions.isEmpty()) {
+                       User owner = folder.getOwner();
+                       PermissionDTO ownerPerm = null;
+                       for (PermissionDTO dto : permissions)
+                               if (dto.getUser() != null && dto.getUser().getId().equals(owner.getId())) {
+                                       ownerPerm = dto;
+                                       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 (PermissionDTO dto : permissions) {
+                               // Skip 'empty' permission entries.
+                               if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
+                               folder.addPermission(getPermission(dto));
+                       }
+                       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);
                }
-               for (Folder sub : folder.getSubfolders())
-                       setFolderPermissions(user, sub, permissions);
        }
 
        private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
@@ -1550,9 +1552,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
 
        }
 
-       /* (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)
@@ -1596,9 +1595,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                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)
@@ -1666,14 +1662,20 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                                Set<PermissionDTO> permissions)
                        throws ObjectNotFoundException, InsufficientPermissionsException {
                if (permissions != null && !permissions.isEmpty()) {
+                       PermissionDTO ownerPerm = null;
+                       for (PermissionDTO dto : permissions)
+                               if (dto.getUser() != null && dto.getUser().getId().equals(file.getOwner().getId())) {
+                                       ownerPerm = dto;
+                                       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");
-                               // Don't include 'empty' permission.
+                               // Skip 'empty' permission entries.
                                if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
                                file.addPermission(getPermission(dto));
                        }
@@ -1714,9 +1716,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                return result;
        }
 
-       /* (non-Javadoc)
-        * @see gr.ebs.gss.server.ejb.ExternalAPI#getSharedFiles(java.lang.Long, java.lang.Long)
-        */
        @Override
        public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
                if (ownerId == null)
@@ -1756,9 +1755,9 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                User user = dao.getEntityById(User.class, userId);
                Folder folder = dao.getEntityById(Folder.class, folderId);
                List<FolderDTO> result = new ArrayList<FolderDTO>();
-               if (folder.isShared(user))
+               if (folder.isShared(user) || folder.isReadForAll())
                        for (Folder f : folder.getSubfolders())
-                               if (f.isShared(user) && !f.isDeleted())
+                               if ((f.isShared(user) || f.isReadForAll()) && !f.isDeleted())
                                        result.add(f.getDTO());
                return result;
        }
@@ -1785,9 +1784,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
 
        }
 
-       /* (non-Javadoc)
-        * @see gr.ebs.gss.server.ejb.ExternalAPI#searchFiles(java.lang.Long, java.lang.String)
-        */
        @Override
        public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
                if (userId == null)
@@ -1805,95 +1801,41 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
        /**
         * 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<FileHeader> search(Long userId, String query) {
+               List<FileHeader> result = new ArrayList<FileHeader>();
                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<FileHeader> fileResult = new ArrayList<FileHeader>();
-                               Node result = lst.getNextSibling().getNextSibling();
-                               NodeList docs = result.getChildNodes();
-                               User user = getUser(userId);
-                               for (int i=1; i<docs.getLength(); i=i+2) {
-                                       Node d = docs.item(i);
-                                       NodeList docData = d.getChildNodes();
-                                       for (int j=1; j<docData.getLength(); j=j+2) {
-                                               Node dd = docData.item(j);
-                                               if (dd.getAttributes().item(0).getNodeName().equals("name") &&
-                                                       dd.getAttributes().item(0).getNodeValue().equals("id")) {
-                                                       Long fileId = Long.valueOf(dd.getTextContent());
-                                                       try {
-                                                               FileHeader file = dao.getEntityById(FileHeader.class, fileId);
-                                                               if (file.hasReadPermission(user)) {
-                                                                       fileResult.add(file);
-                                                                       logger.debug("File added " + fileId);
-                                                               }
-                                                       } catch (ObjectNotFoundException e) {
-                                                               logger.warn("Search result not found", e);
-                                                       }
-                                               }
-                                       }
+                       CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
+                       SolrQuery solrQuery = new SolrQuery(escapeCharacters(normalizeSearchQuery(query)));
+                       QueryResponse response = solr.query(solrQuery);
+                       SolrDocumentList results = response.getResults();
+                       User user = getUser(userId);
+                       for (SolrDocument d : results) {
+                               Long id = Long.valueOf((String) d.getFieldValue("id"));
+                               try {
+                                       FileHeader f = dao.getEntityById(FileHeader.class, id);
+                                       if (f.hasReadPermission(user))
+                                               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) {
+               } catch (MalformedURLException e) {
+                       logger.error(e);
                        throw new EJBException(e);
-               } catch (SAXException 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<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
                for(Long l : fileIds){
@@ -1904,9 +1846,6 @@ 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<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
                for(Long l : fileIds){
@@ -1916,9 +1855,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<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
                if (userId == null)
@@ -1951,9 +1887,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
 
        }
 
-       /* (non-Javadoc)
-        * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFilesToTrash(java.lang.Long, java.util.List)
-        */
        @Override
        public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
                for(Long l : fileIds)
@@ -2004,9 +1937,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)
@@ -2021,9 +1951,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<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
                if (userId == null)
@@ -2040,9 +1967,6 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                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)
@@ -2122,156 +2046,84 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
        }
 
        /**
-        * 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<Long> 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<Long> 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 % 100 == 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("<optimize/>", "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<Long> 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 % 100 == 0) {
+                solr.commit();
+                logger.debug("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);
                }
        }
 
+       @Override
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
                        InsufficientPermissionsException, QuotaExceededException {
@@ -2305,6 +2157,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();
@@ -2339,9 +2193,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
                return file.getDTO();
        }
 
-       /* (non-Javadoc)
-        * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFileContents(java.lang.Long, java.lang.Long, java.lang.String, java.io.InputStream)
-        */
+       @Override
        public FileHeaderDTO 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");
@@ -2420,13 +2272,13 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
         * @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, long fileSize, String filePath,
                                FileHeader header, AuditInfo auditInfo)
-                       throws FileNotFoundException, QuotaExceededException {
+                       throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
 
                long currentTotalSize = 0;
                if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
@@ -2473,6 +2325,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
        }
 
 
+       @Override
        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
        public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
                if (userId == null)
@@ -2506,6 +2359,7 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
        }
 
 
+       @Override
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
 
                if (userId == null)
@@ -2528,6 +2382,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");
@@ -2668,4 +2523,158 @@ public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
 
        }
 
+       @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();
+       }
+
+       /**
+        * Mark the folder as modified from the specified user and change it's modification date.
+        */
+       private void touchFolder(Folder f, User _user, Date now){
+               final AuditInfo auditInfo = f.getAuditInfo();
+               auditInfo.setModificationDate(now);
+               auditInfo.setModifiedBy(_user);
+               f.setAuditInfo(auditInfo);
+       }
+
+       /**
+        * Mark the file as modified from the specified user and change it's modification date.
+        */
+       private void touchFile(FileHeader f, User _user, Date now){
+               final AuditInfo auditInfo = f.getAuditInfo();
+               auditInfo.setModificationDate(now);
+               auditInfo.setModifiedBy(_user);
+               f.setAuditInfo(auditInfo);
+       }
+
+       /**
+        * 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);
+
+               }
+
+       }
+
+       @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());
+                               }
+                File fsFile = new File(body.getStoredFilePath());
+                               solrRequest.addFile(fsFile);
+//                             solrRequest.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
+                               try {
+                                       solr.request(solrRequest);
+                               }
+                               catch (SolrException e) {
+                                       logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
+                                       //Let 's try without the file
+                                       sendMetaDataOnly(solr, file);
+                               }
+                               catch (NullPointerException e) {
+                                       logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
+                                       //Let 's try without the file
+                                       sendMetaDataOnly(solr, file);
+                               }
+                               catch (SolrServerException e) {
+                                       logger.warn("File " + id + " failed with " + 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());
+               }
+               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(":", "\\\\:");
+       }
 }