4cd118d6e412c3ae1b84321a6273f613ba1de08f
[pithos] / gss / src / gr / ebs / gss / server / ejb / ExternalAPIBean.java
1 /*
2  * Copyright 2007, 2008, 2009 Electronic Business Systems Ltd.
3  *
4  * This file is part of GSS.
5  *
6  * GSS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 package gr.ebs.gss.server.ejb;
20
21 import gr.ebs.gss.client.exceptions.DuplicateNameException;
22 import gr.ebs.gss.client.exceptions.GSSIOException;
23 import gr.ebs.gss.client.exceptions.InsufficientPermissionsException;
24 import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
25 import gr.ebs.gss.client.exceptions.QuotaExceededException;
26 import gr.ebs.gss.server.configuration.GSSConfigurationFactory;
27 import gr.ebs.gss.server.domain.AuditInfo;
28 import gr.ebs.gss.server.domain.FileBody;
29 import gr.ebs.gss.server.domain.FileHeader;
30 import gr.ebs.gss.server.domain.FileTag;
31 import gr.ebs.gss.server.domain.FileUploadStatus;
32 import gr.ebs.gss.server.domain.Folder;
33 import gr.ebs.gss.server.domain.Group;
34 import gr.ebs.gss.server.domain.Nonce;
35 import gr.ebs.gss.server.domain.Permission;
36 import gr.ebs.gss.server.domain.User;
37 import gr.ebs.gss.server.domain.dto.FileBodyDTO;
38 import gr.ebs.gss.server.domain.dto.FileHeaderDTO;
39 import gr.ebs.gss.server.domain.dto.FolderDTO;
40 import gr.ebs.gss.server.domain.dto.GroupDTO;
41 import gr.ebs.gss.server.domain.dto.PermissionDTO;
42 import gr.ebs.gss.server.domain.dto.StatsDTO;
43 import gr.ebs.gss.server.domain.dto.UserDTO;
44
45 import java.io.File;
46 import java.io.FileInputStream;
47 import java.io.FileNotFoundException;
48 import java.io.FileOutputStream;
49 import java.io.IOException;
50 import java.io.InputStream;
51 import java.io.StringWriter;
52 import java.io.UnsupportedEncodingException;
53 import java.util.ArrayList;
54 import java.util.Date;
55 import java.util.Iterator;
56 import java.util.LinkedHashSet;
57 import java.util.LinkedList;
58 import java.util.List;
59 import java.util.Random;
60 import java.util.Set;
61 import java.util.StringTokenizer;
62
63 import javax.ejb.EJB;
64 import javax.ejb.EJBException;
65 import javax.ejb.Stateless;
66 import javax.ejb.TransactionAttribute;
67 import javax.ejb.TransactionAttributeType;
68 import javax.jms.Connection;
69 import javax.jms.ConnectionFactory;
70 import javax.jms.JMSException;
71 import javax.jms.MapMessage;
72 import javax.jms.MessageProducer;
73 import javax.jms.Queue;
74 import javax.jms.QueueConnectionFactory;
75 import javax.jms.Session;
76 import javax.jws.WebMethod;
77 import javax.naming.Context;
78 import javax.naming.InitialContext;
79 import javax.naming.NamingException;
80 import javax.xml.parsers.DocumentBuilder;
81 import javax.xml.parsers.DocumentBuilderFactory;
82 import javax.xml.parsers.ParserConfigurationException;
83 import javax.xml.transform.OutputKeys;
84 import javax.xml.transform.Transformer;
85 import javax.xml.transform.TransformerConfigurationException;
86 import javax.xml.transform.TransformerException;
87 import javax.xml.transform.TransformerFactory;
88 import javax.xml.transform.dom.DOMSource;
89 import javax.xml.transform.stream.StreamResult;
90
91 import org.apache.commons.configuration.BaseConfiguration;
92 import org.apache.commons.configuration.ConfigurationException;
93 import org.apache.commons.configuration.DataConfiguration;
94 import org.apache.commons.httpclient.HttpClient;
95 import org.apache.commons.httpclient.HttpException;
96 import org.apache.commons.httpclient.NameValuePair;
97 import org.apache.commons.httpclient.methods.GetMethod;
98 import org.apache.commons.httpclient.methods.PostMethod;
99 import org.apache.commons.httpclient.methods.StringRequestEntity;
100 import org.apache.commons.lang.StringUtils;
101 import org.apache.commons.logging.Log;
102 import org.apache.commons.logging.LogFactory;
103 import org.w3c.dom.DOMException;
104 import org.w3c.dom.Document;
105 import org.w3c.dom.Node;
106 import org.w3c.dom.NodeList;
107 import org.xml.sax.SAXException;
108
109 /**
110  * The concrete implementation of the ExternalAPI interface.
111  *
112  * @author past
113  */
114 @Stateless
115 public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
116
117         /**
118          * Gss configuration
119          */
120         private static DataConfiguration conf = null;
121
122
123         /**
124          * The default MIME type for files without an explicit one.
125          */
126         private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
127
128         /**
129          * The size of the buffer that is used to temporarily store chunks of
130          * uploaded files, while storing them to the file repository.
131          */
132         private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
133
134         /**
135          * The logger.
136          */
137         private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
138
139         static {
140                 try {
141                         conf = GSSConfigurationFactory.getConfiguration();
142                 }
143                 catch (ConfigurationException e) {
144                         // Use empty configuration, so we get no NPE but default values
145                         conf = new DataConfiguration(new BaseConfiguration());
146                         logger.error("Error in ExternalAPI initialization!!! GSS IS RUNNING WITH DEFAULT VALUES",e);
147                 }
148         }
149         /**
150          * Injected reference to the GSSDAO data access facade.
151          */
152         @EJB
153         private GSSDAO dao;
154
155
156         /**
157          * A cached random number generator for creating unique filenames.
158          */
159         private static Random random = new Random();
160
161         @Override
162         public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
163                 if (userId == null)
164                         throw new ObjectNotFoundException("No user specified");
165                 Folder folder = dao.getRootFolder(userId);
166                 return folder.getDTO();
167         }
168
169         /*
170          * (non-Javadoc)
171          *
172          * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolder(java.lang.Long)
173          */
174         public FolderDTO getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
175                 if (userId == null)
176                         throw new ObjectNotFoundException("No user specified");
177                 if (folderId == null)
178                         throw new ObjectNotFoundException("No folder specified");
179                 final User user = dao.getEntityById(User.class, userId);
180                 final Folder folder = dao.getEntityById(Folder.class, folderId);
181                 // Check permissions
182                 if (!folder.hasReadPermission(user))
183                         throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
184                 return folder.getDTO();
185         }
186
187         /* (non-Javadoc)
188          * @see gr.ebs.gss.server.ejb.ExternalAPI#getUser(java.lang.Long)
189          */
190         public User getUser(Long userId) throws ObjectNotFoundException {
191                 if (userId == null)
192                         throw new ObjectNotFoundException("No user specified");
193                 return dao.getEntityById(User.class, userId);
194         }
195
196         /* (non-Javadoc)
197          * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserDTO(java.lang.Long)
198          */
199         public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
200                 return getUser(userId).getDTO();
201         }
202
203         /*
204          * (non-Javadoc)
205          *
206          * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroup(java.lang.Long)
207          */
208         public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
209                 if (groupId == null)
210                         throw new ObjectNotFoundException("No group specified");
211                 final Group group = dao.getEntityById(Group.class, groupId);
212                 return group.getDTO();
213         }
214
215         @Override
216         public GroupDTO getGroup(Long userId, String name) throws ObjectNotFoundException {
217                 if (userId == null)
218                         throw new ObjectNotFoundException("No user specified");
219                 if (name == null)
220                         throw new ObjectNotFoundException("No group specified");
221                 User user = dao.getEntityById(User.class, userId);
222                 List<Group> groups = user.getGroupsSpecified();
223                 for (Group group: groups)
224                         if (group.getName().equals(name))
225                                 return group.getDTO();
226                 throw new ObjectNotFoundException("Group " + name + " not found");
227         }
228
229         /*
230          * (non-Javadoc)
231          *
232          * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroups(java.lang.Long)
233          */
234         public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
235                 if (userId == null)
236                         throw new ObjectNotFoundException("No user specified");
237                 final List<Group> groups = dao.getGroups(userId);
238                 final List<GroupDTO> result = new ArrayList<GroupDTO>();
239                 for (final Group g : groups)
240                         result.add(g.getDTO());
241                 return result;
242         }
243
244         @Override
245         public List<FileHeaderDTO> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
246                         throws ObjectNotFoundException, InsufficientPermissionsException {
247                 // Validate.
248                 if (userId == null)
249                         throw new ObjectNotFoundException("No user specified");
250                 if (folderId == null)
251                         throw new ObjectNotFoundException("No folder specified");
252                 User user = dao.getEntityById(User.class, userId);
253                 Folder folder = dao.getEntityById(Folder.class, folderId);
254                 if (!folder.hasReadPermission(user))
255                         throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
256                 // Do the actual work.
257                 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
258                 List<FileHeader> files = dao.getFiles(folderId, ignoreDeleted);
259                 for (FileHeader f : files)
260                         result.add(f.getDTO());
261                 return result;
262         }
263
264         /*
265          * (non-Javadoc)
266          *
267          * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsers(java.lang.Long,
268          *      java.lang.Long)
269          */
270         public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
271                 // Validate.
272                 if (userId == null)
273                         throw new ObjectNotFoundException("No user specified");
274                 if (groupId == null)
275                         throw new ObjectNotFoundException("No group specified");
276
277                 // Do the actual work.
278                 final List<User> users = dao.getUsers(groupId);
279                 final List<UserDTO> result = new ArrayList<UserDTO>();
280                 for (final User u : users)
281                         result.add(u.getDTO());
282                 return result;
283         }
284
285         @Override
286         public void createFolder(Long userId, Long parentId, String name)
287                         throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
288                 // Validate.
289                 if (userId == null)
290                         throw new ObjectNotFoundException("No user specified");
291                 if (StringUtils.isEmpty(name))
292                         throw new ObjectNotFoundException("New folder name is empty");
293                 if (parentId == null)
294                         throw new ObjectNotFoundException("No parent specified");
295                 if (dao.existsFolderOrFile(parentId, name))
296                         throw new DuplicateNameException("A folder or file with the name '" +
297                                                 name + "' already exists at this level");
298
299                 User creator = dao.getEntityById(User.class, userId);
300
301                 Folder parent = null;
302                 try {
303                         parent = dao.getEntityById(Folder.class, parentId);
304                 } catch (ObjectNotFoundException onfe) {
305                         // Supply a more accurate problem description.
306                         throw new ObjectNotFoundException("Parent folder not found");
307                 }
308                 if (!parent.hasWritePermission(creator))
309                         throw new InsufficientPermissionsException("You don't have the permissions" +
310                                         " to write to this folder");
311
312                 // Do the actual work.
313                 createFolder(name, parent, creator);
314         }
315
316         /**
317          * Create a new folder with the provided name, parent and owner.
318          *
319          * @param name
320          * @param parent
321          * @param creator
322          * @param owner
323          */
324         private void createFolder(String name, Folder parent, User creator) {
325                 Folder folder = new Folder();
326                 folder.setName(name);
327                 if (parent != null) {
328                         parent.addSubfolder(folder);
329                         folder.setOwner(parent.getOwner());
330                 } else
331                         folder.setOwner(creator);
332
333                 Date now = new Date();
334                 AuditInfo auditInfo = new AuditInfo();
335                 auditInfo.setCreatedBy(creator);
336                 auditInfo.setCreationDate(now);
337                 auditInfo.setModifiedBy(creator);
338                 auditInfo.setModificationDate(now);
339                 folder.setAuditInfo(auditInfo);
340
341                 if (parent != null)
342                         for (Permission p : parent.getPermissions()) {
343                                 Permission permission = new Permission();
344                                 permission.setGroup(p.getGroup());
345                                 permission.setUser(p.getUser());
346                                 permission.setRead(p.getRead());
347                                 permission.setWrite(p.getWrite());
348                                 permission.setModifyACL(p.getModifyACL());
349                                 folder.addPermission(permission);
350                         }
351                 else {
352                         Permission permission = new Permission();
353                         permission.setUser(creator);
354                         permission.setRead(true);
355                         permission.setWrite(true);
356                         permission.setModifyACL(true);
357                         folder.addPermission(permission);
358                 }
359                 dao.create(folder);
360         }
361
362         /*
363          * (non-Javadoc)
364          *
365          * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFolder(java.lang.Long,
366          *      java.lang.Long)
367          */
368         public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
369                 // Validate.
370                 if (userId == null)
371                         throw new ObjectNotFoundException("No user specified");
372                 if (folderId == null)
373                         throw new ObjectNotFoundException("No folder specified");
374
375                 // Do the actual work.
376                 final Folder folder = dao.getEntityById(Folder.class, folderId);
377                 final Folder parent = folder.getParent();
378                 if (parent == null)
379                         throw new ObjectNotFoundException("Deleting the root folder is not allowed");
380                 final User user = dao.getEntityById(User.class, userId);
381                 if (!folder.hasDeletePermission(user)) {
382                         logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
383                         throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
384                 }
385                 parent.removeSubfolder(folder);
386                 dao.delete(folder);
387         }
388
389         @SuppressWarnings("unchecked")
390         public List<FolderDTO> getSubfolders(Long userId, Long folderId)
391                         throws ObjectNotFoundException, InsufficientPermissionsException {
392                 if (userId == null)
393                         throw new ObjectNotFoundException("No user specified");
394                 if (folderId == null)
395                         throw new ObjectNotFoundException("No folder specified");
396                 User user = dao.getEntityById(User.class, userId);
397                 Folder folder = dao.getEntityById(Folder.class, folderId);
398                 if (!folder.hasReadPermission(user))
399                         throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
400                 List<FolderDTO> result = new ArrayList<FolderDTO>();
401                 if (folder.hasReadPermission(user))
402                         for (Folder f : folder.getSubfolders())
403                                 if (f.hasReadPermission(user) && !f.isDeleted())
404                                         result.add(f.getDTO());
405                 return result;
406         }
407
408         @Override
409         public void modifyFolder(Long userId, Long folderId, String folderName)
410                         throws InsufficientPermissionsException, ObjectNotFoundException, DuplicateNameException {
411
412                 // Validate.
413                 if (userId == null)
414                         throw new ObjectNotFoundException("No user specified");
415                 if (folderId == null)
416                         throw new ObjectNotFoundException("No folder specified");
417                 if (StringUtils.isEmpty(folderName))
418                         throw new ObjectNotFoundException("New folder name is empty");
419
420                 Folder folder = dao.getEntityById(Folder.class, folderId);
421                 User user = dao.getEntityById(User.class, userId);
422                 if (!folder.hasWritePermission(user))
423                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
424
425                 Folder parent = folder.getParent();
426                 if (parent != null)
427                         if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
428                                 throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
429
430                 // Do the actual modification.
431                 folder.setName(folderName);
432                 dao.update(folder);
433         }
434
435         /*
436          * (non-Javadoc)
437          *
438          * @see gr.ebs.gss.server.ejb.ExternalAPI#createGroup(java.lang.Long,
439          *      java.lang.String)
440          */
441         public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
442                 // Validate.
443                 if (userId == null)
444                         throw new ObjectNotFoundException("No user specified");
445                 if (StringUtils.isEmpty(name))
446                         throw new ObjectNotFoundException("New group name is empty");
447                 if (dao.existsGroup(userId, name))
448                         throw new DuplicateNameException("A group with the name '" + name + "' already exists");
449
450                 // TODO: Check permissions
451
452                 final User owner = dao.getEntityById(User.class, userId);
453
454                 // Do the actual work.
455                 owner.createGroup(name);
456         }
457
458         /*
459          * (non-Javadoc)
460          *
461          * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteGroup(java.lang.Long,
462          *      java.lang.Long)
463          */
464         public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
465                 // Validate.
466                 if (userId == null)
467                         throw new ObjectNotFoundException("No user specified");
468                 if (groupId == null)
469                         throw new ObjectNotFoundException("No group specified");
470
471                 // Do the actual work.
472                 final User owner = dao.getEntityById(User.class, userId);
473                 final Group group = dao.getEntityById(Group.class, groupId);
474                 // Only delete the group if actually owned by the user.
475                 if (group.getOwner().equals(owner)) {
476                         List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
477                         for (Folder f : folders){
478                                 f.getPermissions().removeAll(group.getPermissions());
479                                 for(FileHeader file : f.getFiles())
480                                         file.getPermissions().removeAll(group.getPermissions());
481                         }
482                         List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
483                         for(FileHeader h : files)
484                                 h.getPermissions().removeAll(group.getPermissions());
485                         owner.removeSpecifiedGroup(group);
486                         dao.delete(group);
487                 }
488                 else throw new InsufficientPermissionsException("You are not the owner of this group");
489         }
490
491         @Override
492         public void createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
493                         throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
494                         InsufficientPermissionsException, QuotaExceededException {
495                 File file = null;
496                 try {
497                         file = uploadFile(stream, userId);
498                 } catch ( IOException ioe) {
499                         // Supply a more accurate problem description.
500                         throw new GSSIOException("Problem creating file",ioe);
501                 }
502                 createFile(userId, folderId, name, mimeType, file);
503         }
504
505         /* (non-Javadoc)
506          * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
507          */
508         public void indexFile(Long fileId, boolean delete) {
509                 Connection qConn = null;
510                 Session session = null;
511                 MessageProducer sender = null;
512                 try {
513                         Context jndiCtx = new InitialContext();
514                         ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
515                         Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
516                         qConn = factory.createConnection();
517                         session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
518                         sender = session.createProducer(queue);
519
520                         MapMessage map = session.createMapMessage();
521                         map.setObject("id", fileId);
522                         map.setBoolean("delete", delete);
523                         sender.send(map);
524                 }
525                 catch (NamingException e) {
526                         logger.error("Index was not updated: ", e);
527                 }
528                 catch (JMSException e) {
529                         logger.error("Index was not updated: ", e);
530                 }
531                 finally {
532                         try {
533                                 if (sender != null)
534                                         sender.close();
535                                 if (session != null)
536                                         session.close();
537                                 if (qConn != null)
538                                         qConn.close();
539                         }
540                         catch (JMSException e) {
541                                 logger.warn(e);
542                         }
543                 }
544         }
545
546
547
548         /**
549          * A helper method that generates a unique file path for a stored file. The
550          * files are stored using random hash names that are distributed evenly in
551          * a 2-level tree of subdirectories named after the first two hex characters
552          * in the name. For example, file ab1234cd5769f will be stored in the path
553          * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
554          * if they don't already exist.
555          *
556          * @return a unique new file path
557          */
558         private String generateRepositoryFilePath() {
559                 String filename = Long.toHexString(random.nextLong());
560                 String fileRepositoryPath = conf.getString("fileRepositoryPath","/tmp");
561                 File root = new File(fileRepositoryPath);
562                 if (!root.exists())
563                         root.mkdirs();
564                 File firstFolder = new File(root + File.separator + filename.substring(0, 1));
565                 if (!firstFolder.exists())
566                         firstFolder.mkdir();
567                 File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
568                 if (!secondFolder.exists())
569                         secondFolder.mkdir();
570                 return secondFolder + File.separator + filename;
571         }
572
573         /*
574          * (non-Javadoc)
575          *
576          * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFile(java.lang.Long,
577          *      java.lang.Long)
578          */
579         public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
580                 // Validate.
581                 if (userId == null)
582                         throw new ObjectNotFoundException("No user specified");
583                 if (fileId == null)
584                         throw new ObjectNotFoundException("No file specified");
585
586                 // Do the actual work.
587                 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
588                 final Folder parent = file.getFolder();
589                 if (parent == null)
590                         throw new ObjectNotFoundException("The specified file has no parent folder");
591                 final User user = dao.getEntityById(User.class, userId);
592                 if (!file.hasDeletePermission(user))
593                         throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
594                 for (final FileBody body : file.getBodies()) {
595                         final File fileContents = new File(body.getStoredFilePath());
596                         if (!fileContents.delete())
597                                 logger.error("Could not delete file " + body.getStoredFilePath());
598                 }
599                 dao.delete(file);
600                 indexFile(fileId, true);
601         }
602
603         /*
604          * (non-Javadoc)
605          *
606          * @see gr.ebs.gss.server.ejb.ExternalAPI#createTag(java.lang.Long,
607          *      java.lang.Long, java.lang.String)
608          */
609         public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
610                 if (userId == null)
611                         throw new ObjectNotFoundException("No user specified");
612                 if (fileHeaderId == null)
613                         throw new ObjectNotFoundException("No file specified");
614                 if (StringUtils.isEmpty(tag))
615                         throw new ObjectNotFoundException("Tag is empty");
616
617                 final User user = dao.getEntityById(User.class, userId);
618                 final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
619                 user.addTag(fh, tag);
620         }
621
622         /* (non-Javadoc)
623          * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserTags(java.lang.Long)
624          */
625         @WebMethod(operationName = "getUserTags")
626         public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
627                 return dao.getUserTags(userId);
628         }
629
630         /* (non-Javadoc)
631          * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFile(java.lang.Long, java.lang.Long, java.lang.String, java.util.Set)
632          */
633         public void updateFile(Long userId, Long fileId, String name, String tagSet) throws ObjectNotFoundException, InsufficientPermissionsException {
634                 if (userId == null)
635                         throw new ObjectNotFoundException("No user specified");
636                 if (fileId == null)
637                         throw new ObjectNotFoundException("No file specified");
638                 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
639                 User user = dao.getEntityById(User.class, userId);
640                 if (!file.hasWritePermission(user))
641                         throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
642
643                 if (name != null)
644                         file.setName(name);
645                 List<FileTag> tags = file.getFileTags();
646
647                 if (tagSet != null) {
648                         Iterator<FileTag> i = tags.iterator();
649                         while (i.hasNext()) {
650                                 FileTag tag = i.next();
651                                 i.remove();
652                                 tag.setFile(null);
653                                 user.removeTag(tag);
654                                 dao.delete(tag);
655                         }
656                         dao.flush();
657                         StringTokenizer st = new StringTokenizer(tagSet, ",");
658                         while (st.hasMoreTokens())
659                                 new FileTag(user, file, st.nextToken().trim());
660                 }
661
662                 // Re-index the file if it was modified.
663                 if (name != null || tagSet != null)
664                         indexFile(fileId, false);
665         }
666
667         @Override
668         public InputStream getFileContents(Long userId, Long fileId)
669                         throws ObjectNotFoundException, InsufficientPermissionsException {
670                 if (userId == null)
671                         throw new ObjectNotFoundException("No user specified");
672                 if (fileId == null)
673                         throw new ObjectNotFoundException("No file specified");
674
675                 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
676                 User user = dao.getEntityById(User.class, userId);
677                 if (!header.hasReadPermission(user)) {
678                         logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
679                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
680                 }
681
682                 File f = new File(header.getCurrentBody().getStoredFilePath());
683                 try {
684                         return new FileInputStream(f);
685                 } catch (FileNotFoundException e) {
686                         logger.error("Could not locate the contents of file " + f.getAbsolutePath());
687                         throw new ObjectNotFoundException("The file contents could not be located");
688                 }
689         }
690
691         /* (non-Javadoc)
692          * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
693          */
694         public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
695                 if (userId == null)
696                         throw new ObjectNotFoundException("No user specified");
697                 if (fileId == null)
698                         throw new ObjectNotFoundException("No file specified");
699                 if (bodyId == null)
700                         throw new ObjectNotFoundException("No file specified");
701
702                 final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
703                 final FileBody body = dao.getEntityById(FileBody.class, bodyId);
704                 final User user = dao.getEntityById(User.class, userId);
705                 if (!header.hasReadPermission(user)) {
706                         logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
707                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
708                 }
709
710                 File f = new File(body.getStoredFilePath());
711                 try {
712                         return new FileInputStream(f);
713                 } catch (FileNotFoundException e) {
714                         logger.error("Could not locate the contents of file " + f.getAbsolutePath());
715                         throw new ObjectNotFoundException("The file contents could not be located");
716                 }
717         }
718
719         /* (non-Javadoc)
720          * @see gr.ebs.gss.server.ejb.ExternalAPI#getFile(java.lang.Long, java.lang.Long)
721          */
722         public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
723                 if (userId == null)
724                         throw new ObjectNotFoundException("No user specified");
725                 if (fileId == null)
726                         throw new ObjectNotFoundException("No file specified");
727                 final User user = dao.getEntityById(User.class, userId);
728                 final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
729                 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
730                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
731                 return file.getDTO();
732         }
733
734         @Override
735         public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
736                 if (userId == null)
737                         throw new ObjectNotFoundException("No user specified");
738                 if (fileId == null)
739                         throw new ObjectNotFoundException("No file specified");
740                 User user = dao.getEntityById(User.class, userId);
741                 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
742                 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
743                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
744                 FileBody body = dao.getEntityById(FileBody.class, bodyId);
745                 return body.getDTO();
746         }
747
748         @Override
749         public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
750                         throws ObjectNotFoundException {
751                 if (ownerId == null)
752                         throw new ObjectNotFoundException("No user specified");
753                 if (StringUtils.isEmpty(path))
754                         throw new ObjectNotFoundException("No path specified");
755
756                 User owner = dao.getEntityById(User.class, ownerId);
757                 List<String> pathElements = new ArrayList<String>();
758                 StringTokenizer st = new StringTokenizer(path, "/");
759                 while (st.hasMoreTokens())
760                         pathElements.add(st.nextToken());
761                 if (pathElements.size() < 1)
762                         return getRootFolder(owner.getId());
763                 // Store the last element, since it requires special handling.
764                 String lastElement = pathElements.remove(pathElements.size() - 1);
765                 FolderDTO cursor = getRootFolder(owner.getId());
766                 // Traverse and verify the specified folder path.
767                 for (String pathElement : pathElements) {
768                         cursor = getFolder(cursor.getId(), pathElement);
769                         if (cursor.isDeleted())
770                                 throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
771                 }
772
773                 // Use the lastElement to retrieve the actual resource.
774                 Object resource = null;
775                 try {
776                         FileHeaderDTO file = getFile(cursor.getId(), lastElement);
777                         if (ignoreDeleted && file.isDeleted())
778                                 throw new ObjectNotFoundException("Resource not found");
779                         resource = file;
780                 } catch (ObjectNotFoundException e) {
781                         // Perhaps the requested resource is not a file, so
782                         // check for folders as well.
783                         FolderDTO folder = getFolder(cursor.getId(), lastElement);
784                         if (ignoreDeleted && folder.isDeleted())
785                                 throw new ObjectNotFoundException("Resource not found");
786                         resource = folder;
787                 }
788                 return resource;
789         }
790
791         /**
792          * Retrieve a file for the specified user that has the specified name and
793          * its parent folder has id equal to folderId.
794          *
795          * @param userId the ID of the current user
796          * @param folderId the ID of the parent folder
797          * @param name the name of the requested file
798          * @return the file found
799          * @throws ObjectNotFoundException if the specified folder or file was not
800          *             found, with the exception message mentioning the precise
801          *             problem
802          */
803         private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
804                 if (folderId == null)
805                         throw new ObjectNotFoundException("No parent folder specified");
806                 if (StringUtils.isEmpty(name))
807                         throw new ObjectNotFoundException("No file specified");
808
809                 FileHeader file = dao.getFile(folderId, name);
810                 return file.getDTO();
811         }
812
813         /**
814          * Retrieve a folder for the specified user that has the specified name and
815          * its parent folder has id equal to parentId.
816          *
817          * @param parentId the ID of the parent folder
818          * @param name the name of the requested folder
819          * @return the folder found
820          * @throws ObjectNotFoundException if the specified folder or parent was not
821          *             found, with the exception message mentioning the precise
822          *             problem
823          */
824         private FolderDTO getFolder(Long parentId, String name) throws ObjectNotFoundException {
825                 if (parentId == null)
826                         throw new ObjectNotFoundException("No parent folder specified");
827                 if (StringUtils.isEmpty(name))
828                         throw new ObjectNotFoundException("No folder specified");
829
830                 Folder folder = dao.getFolder(parentId, name);
831                 return folder.getDTO();
832         }
833
834         @Override
835         public void updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
836                 File file = null;
837                 try {
838                         file = uploadFile(resourceInputStream, userId);
839                 } catch ( IOException ioe) {
840                         // Supply a more accurate problem description.
841                         throw new GSSIOException("Problem creating file",ioe);
842                 }
843                 updateFileContents(userId, fileId, mimeType, file);
844         }
845
846         @Override
847         public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
848                 if (userId == null)
849                         throw new ObjectNotFoundException("No user specified");
850                 if (fileId == null)
851                         throw new ObjectNotFoundException("No file specified");
852                 if (StringUtils.isEmpty(dest))
853                         throw new ObjectNotFoundException("No destination specified");
854
855                 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
856                 if (!(destination instanceof FolderDTO))
857                         throw new ObjectNotFoundException("Destination parent folder not found");
858                 FolderDTO parent = (FolderDTO) destination;
859                 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
860         }
861
862         @Override
863         public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
864                 if (userId == null)
865                         throw new ObjectNotFoundException("No user specified");
866                 if (ownerId == null)
867                         throw new ObjectNotFoundException("No owner specified");
868                 if (fileId == null)
869                         throw new ObjectNotFoundException("No file specified");
870                 if (StringUtils.isEmpty(dest))
871                         throw new ObjectNotFoundException("No destination specified");
872
873                 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
874                 if (!(destination instanceof FolderDTO))
875                         throw new ObjectNotFoundException("Destination parent folder not found");
876                 FolderDTO parent = (FolderDTO) destination;
877                 copyFile(userId, fileId, parent.getId(), getLastElement(dest));
878         }
879
880         @Override
881         public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
882                 if (userId == null)
883                         throw new ObjectNotFoundException("No user specified");
884                 if (fileId == null)
885                         throw new ObjectNotFoundException("No file specified");
886                 if (destId == null)
887                         throw new ObjectNotFoundException("No destination specified");
888                 if (StringUtils.isEmpty(destName))
889                         throw new ObjectNotFoundException("No destination file name specified");
890
891                 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
892                 Folder destination = dao.getEntityById(Folder.class, destId);
893                 User user = dao.getEntityById(User.class, userId);
894                 if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
895                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
896                 int versionsNumber = file.getBodies().size();
897                 FileBody oldestBody = file.getBodies().get(0);
898                 assert oldestBody != null;
899                 File contents = new File(oldestBody.getStoredFilePath());
900                 try {
901                         createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
902                         FileHeader copiedFile = dao.getFile(destination.getId(), destName);
903                         dao.flush();
904                         if (versionsNumber > 1)
905                                 for (int i = 1; i < versionsNumber; i++) {
906                                         FileBody body = file.getBodies().get(i);
907                                         assert body != null;
908                                         contents = new File(body.getStoredFilePath());
909                                         updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
910                                 }
911                         List<FileTag> tags = file.getFileTags();
912                         for (FileTag tag : tags)
913                                 createTag(userId, copiedFile.getId(), tag.getTag());
914
915                 } catch (FileNotFoundException e) {
916                         throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
917                 }
918
919         }
920
921         @Override
922         public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
923                 if (userId == null)
924                         throw new ObjectNotFoundException("No user specified");
925                 if (folderId == null)
926                         throw new ObjectNotFoundException("No folder specified");
927                 if (StringUtils.isEmpty(dest))
928                         throw new ObjectNotFoundException("No destination specified");
929
930                 Object destination = getResourceAtPath(userId, getParentPath(dest), true);
931                 if (!(destination instanceof FolderDTO))
932                         throw new ObjectNotFoundException("Destination folder not found");
933                 FolderDTO parent = (FolderDTO) destination;
934                 copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
935         }
936
937         @Override
938         public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
939                 if (userId == null)
940                         throw new ObjectNotFoundException("No user specified");
941                 if (folderId == null)
942                         throw new ObjectNotFoundException("No folder specified");
943                 if (destId == null)
944                         throw new ObjectNotFoundException("No destination specified");
945                 if (StringUtils.isEmpty(destName))
946                         throw new ObjectNotFoundException("No destination folder name specified");
947                 Folder folder = dao.getEntityById(Folder.class, folderId);
948                 Folder destination = dao.getEntityById(Folder.class, destId);
949                 User user = dao.getEntityById(User.class, userId);
950                 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
951                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
952                 createFolder(user.getId(), destination.getId(), destName);
953         }
954
955         @Override
956         public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
957                 if (userId == null)
958                         throw new ObjectNotFoundException("No user specified");
959                 if (ownerId == null)
960                         throw new ObjectNotFoundException("No owner specified");
961                 if (folderId == null)
962                         throw new ObjectNotFoundException("No folder specified");
963                 if (StringUtils.isEmpty(dest))
964                         throw new ObjectNotFoundException("No destination specified");
965
966                 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
967                 if (!(destination instanceof FolderDTO))
968                         throw new ObjectNotFoundException("Destination folder not found");
969                 FolderDTO parent = (FolderDTO) destination;
970                 copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
971         }
972
973         @Override
974         public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
975                 if (userId == null)
976                         throw new ObjectNotFoundException("No user specified");
977                 if (folderId == null)
978                         throw new ObjectNotFoundException("No folder specified");
979                 if (destId == null)
980                         throw new ObjectNotFoundException("No destination specified");
981                 if (StringUtils.isEmpty(destName))
982                         throw new ObjectNotFoundException("No destination folder name specified");
983
984                 Folder folder = dao.getEntityById(Folder.class, folderId);
985                 Folder destination = dao.getEntityById(Folder.class, destId);
986                 final User user = dao.getEntityById(User.class, userId);
987                 // XXX: quick fix need to copy only visible items to user (Source
988                 // for bugs)
989                 if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
990                         return;
991                 if(folder.isDeleted())//do not copy trashed folder and contents
992                         return;
993                 if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
994                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
995                 createFolder(user.getId(), destination.getId(), destName);
996                 Folder createdFolder = dao.getFolder(destination.getId(), destName);
997                 List<FileHeader> files = folder.getFiles();
998                 if (files != null)
999                         for (FileHeader file : files)
1000                                 if(!file.isDeleted())
1001                                         copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1002                 List<Folder> subFolders = folder.getSubfolders();
1003                 if (subFolders != null)
1004                         for (Folder sub : subFolders)
1005                                 if(!sub.getId().equals(createdFolder.getId()))
1006                                         copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1007
1008         }
1009
1010         /**
1011          * For a provided path, remove the last element and return the rest, that is
1012          * the path of the parent folder.
1013          *
1014          * @param path the specified path
1015          * @return the path of the parent folder
1016          * @throws ObjectNotFoundException if the provided string contains no path
1017          *             delimiters
1018          */
1019         private String getParentPath(String path) throws ObjectNotFoundException {
1020                 int lastDelimiter = path.lastIndexOf('/');
1021                 if (lastDelimiter == 0)
1022                         return "/";
1023                 if (lastDelimiter == -1)
1024                         // No path found.
1025                         throw new ObjectNotFoundException("There is no parent in the path: " + path);
1026                 else if (lastDelimiter < path.length() - 1)
1027                         // Return the part before the delimiter.
1028                         return path.substring(0, lastDelimiter);
1029                 else {
1030                         // Remove the trailing delimiter and then recurse.
1031                         String strippedTrail = path.substring(0, lastDelimiter);
1032                         return getParentPath(strippedTrail);
1033                 }
1034         }
1035
1036         /**
1037          * Get the last element in a path that denotes the file or folder name.
1038          *
1039          * @param path the provided path
1040          * @return the last element in the path
1041          */
1042         private String getLastElement(String path) {
1043                 int lastDelimiter = path.lastIndexOf('/');
1044                 if (lastDelimiter == -1)
1045                         // No path found.
1046                         return path;
1047                 else if (lastDelimiter < path.length() - 1)
1048                         // Return the part after the delimiter.
1049                         return path.substring(lastDelimiter + 1);
1050                 else {
1051                         // Remove the trailing delimiter and then recurse.
1052                         String strippedTrail = path.substring(0, lastDelimiter);
1053                         return getLastElement(strippedTrail);
1054                 }
1055         }
1056
1057         @Override
1058         public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1059                 if (userId == null)
1060                         throw new ObjectNotFoundException("No user specified");
1061                 if (fileId == null)
1062                         throw new ObjectNotFoundException("No file specified");
1063
1064                 // Do the actual work.
1065                 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1066                 Folder parent = file.getFolder();
1067                 if (parent == null)
1068                         throw new ObjectNotFoundException("The specified file has no parent folder");
1069                 User user = dao.getEntityById(User.class, userId);
1070                 if (!file.hasDeletePermission(user))
1071                         throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1072
1073                 file.setDeleted(true);
1074                 dao.update(file);
1075         }
1076
1077         @Override
1078         public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, DuplicateNameException, GSSIOException, QuotaExceededException {
1079                 if (userId == null)
1080                         throw new ObjectNotFoundException("No user specified");
1081                 if (ownerId == null)
1082                         throw new ObjectNotFoundException("No owner specified");
1083                 if (fileId == null)
1084                         throw new ObjectNotFoundException("No file specified");
1085                 if (StringUtils.isEmpty(dest))
1086                         throw new ObjectNotFoundException("No destination specified");
1087
1088                 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1089                 if (!(destination instanceof FolderDTO))
1090                         throw new ObjectNotFoundException("Destination parent folder not found");
1091                 FolderDTO parent = (FolderDTO) destination;
1092                 moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1093         }
1094
1095         @Override
1096         public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, DuplicateNameException, GSSIOException, QuotaExceededException {
1097                 if (userId == null)
1098                         throw new ObjectNotFoundException("No user specified");
1099                 if (fileId == null)
1100                         throw new ObjectNotFoundException("No file specified");
1101                 if (destId == null)
1102                         throw new ObjectNotFoundException("No destination specified");
1103                 if (StringUtils.isEmpty(destName))
1104                         throw new ObjectNotFoundException("No destination file name specified");
1105
1106                 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1107                 Folder destination = dao.getEntityById(Folder.class, destId);
1108
1109                 User owner = dao.getEntityById(User.class, userId);
1110                 if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1111                         throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1112                 FileBody body = file.getCurrentBody();
1113                 assert body != null;
1114                 File contents = new File(body.getStoredFilePath());
1115                 try {
1116                         createFile(owner.getId(), destination.getId(), destName, body.getMimeType(), new FileInputStream(contents));
1117                 } catch (FileNotFoundException e) {
1118                         throw new ObjectNotFoundException("File contents not found for file " + body.getStoredFilePath());
1119                 }
1120                 deleteFile(userId, fileId);
1121
1122         }
1123
1124         @Override
1125         public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1126                 if (userId == null)
1127                         throw new ObjectNotFoundException("No user specified");
1128                 if (ownerId == null)
1129                         throw new ObjectNotFoundException("No owner specified");
1130                 if (folderId == null)
1131                         throw new ObjectNotFoundException("No folder specified");
1132                 if (StringUtils.isEmpty(dest))
1133                         throw new ObjectNotFoundException("No destination specified");
1134
1135                 Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1136                 if (!(destination instanceof FolderDTO))
1137                         throw new ObjectNotFoundException("Destination parent folder not found");
1138                 FolderDTO parent = (FolderDTO) destination;
1139                 moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1140         }
1141
1142         @Override
1143         public void moveFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1144                 // TODO Simple Move and delete of original folder, in production
1145                 // scenario we must first check individual files and folders permissions
1146                 copyFolderStructure(userId, folderId, destId, destName);
1147                 deleteFolder(userId, folderId);
1148         }
1149
1150         /* (non-Javadoc)
1151          * @see gr.ebs.gss.server.ejb.ExternalAPI#getDeletedFiles(java.lang.Long)
1152          */
1153         public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1154                 // Validate.
1155                 if (userId == null)
1156                         throw new ObjectNotFoundException("No user specified");
1157
1158                 // Do the actual work.
1159                 final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1160                 final List<FileHeader> files = dao.getDeletedFiles(userId);
1161                 for (final FileHeader f : files)
1162                         result.add(f.getDTO());
1163                 return result;
1164         }
1165
1166         @Override
1167         public void removeFileFromTrash(Long userId, Long fileId)
1168                         throws ObjectNotFoundException, InsufficientPermissionsException {
1169                 if (userId == null)
1170                         throw new ObjectNotFoundException("No user specified");
1171                 if (fileId == null)
1172                         throw new ObjectNotFoundException("No file specified");
1173
1174                 // Do the actual work.
1175                 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1176                 Folder parent = file.getFolder();
1177                 if (parent == null)
1178                         throw new ObjectNotFoundException("The specified file has no parent folder");
1179                 User user = dao.getEntityById(User.class, userId);
1180                 if (!file.hasDeletePermission(user))
1181                         throw new InsufficientPermissionsException("User " + user.getUsername() +
1182                                                 " cannot restore file " + file.getName());
1183
1184                 file.setDeleted(false);
1185                 dao.update(file);
1186         }
1187
1188         @Override
1189         public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1190                 if (userId == null)
1191                         throw new ObjectNotFoundException("No user specified");
1192                 if (folderId == null)
1193                         throw new ObjectNotFoundException("No folder specified");
1194                 Folder folder = dao.getEntityById(Folder.class, folderId);
1195                 User user = dao.getEntityById(User.class, userId);
1196                 if (!folder.hasDeletePermission(user))
1197                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
1198                 folder.setDeleted(true);
1199                 dao.update(folder);
1200                 for (FileHeader file : folder.getFiles())
1201                         moveFileToTrash(userId, file.getId());
1202                 for (Folder subFolder : folder.getSubfolders())
1203                         moveFolderToTrash(userId, subFolder.getId());
1204
1205         }
1206
1207         @Override
1208         public void removeFolderFromTrash(Long userId, Long folderId)
1209                         throws ObjectNotFoundException, InsufficientPermissionsException {
1210                 if (userId == null)
1211                         throw new ObjectNotFoundException("No user specified");
1212                 if (folderId == null)
1213                         throw new ObjectNotFoundException("No folder specified");
1214                 Folder folder = dao.getEntityById(Folder.class, folderId);
1215                 User user = dao.getEntityById(User.class, userId);
1216                 if (!folder.hasDeletePermission(user))
1217                         throw new InsufficientPermissionsException("User " + user.getUsername() +
1218                                                 " cannot restore folder " + folder.getName());
1219                 folder.setDeleted(false);
1220                 for (FileHeader file : folder.getFiles())
1221                         removeFileFromTrash(userId, file.getId());
1222                 for (Folder subFolder : folder.getSubfolders())
1223                         removeFolderFromTrash(userId, subFolder.getId());
1224                 dao.update(folder);
1225         }
1226
1227         @Override
1228         public List<FolderDTO> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1229                 List<Folder> folders = dao.getDeletedRootFolders(userId);
1230                 List<FolderDTO> result = new ArrayList<FolderDTO>();
1231                 for (Folder folder : folders)
1232                         result.add(folder.getDTO());
1233                 return result;
1234         }
1235
1236         @Override
1237         public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1238                 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1239                 for (FolderDTO fdto : deletedRootFolders)
1240                         deleteFolder(userId, fdto.getId());
1241                 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1242                 for (FileHeaderDTO filedto : deletedFiles)
1243                         deleteFile(userId, filedto.getId());
1244         }
1245
1246         @Override
1247         public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1248                 List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1249                 for (FolderDTO fdto : deletedRootFolders)
1250                         removeFolderFromTrash(userId, fdto.getId());
1251                 List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1252                 for (FileHeaderDTO filedto : deletedFiles)
1253                         removeFileFromTrash(userId, filedto.getId());
1254         }
1255
1256         @Override
1257         public User createUser(String username, String name, String mail) throws ObjectNotFoundException {
1258                 if (username == null)
1259                         throw new ObjectNotFoundException("No username specified");
1260                 if (name == null)
1261                         throw new ObjectNotFoundException("No name specified");
1262
1263                 User user = new User();
1264                 user.setUsername(username);
1265                 user.setName(name);
1266                 user.setEmail(mail);
1267                 Date now = new Date();
1268                 AuditInfo auditInfo = new AuditInfo();
1269                 auditInfo.setCreationDate(now);
1270                 auditInfo.setModificationDate(now);
1271                 user.setAuditInfo(auditInfo);
1272                 user.generateAuthToken();
1273                 dao.create(user);
1274                 // Make sure we get an ID in the user object.
1275                 dao.flush();
1276                 // Create the root folder for the user.
1277                 createFolder(user.getName(), null, user);
1278                 return user;
1279         }
1280
1281         @Override
1282         public User findUserByEmail(String email) {
1283                 return dao.findUserByEmail(email);
1284         }
1285
1286         @Override
1287         public void updateUser(User user) {
1288                 dao.update(user);
1289         }
1290
1291         @Override
1292         public User updateUser(String username, String name, String mail) throws ObjectNotFoundException {
1293                 if (username == null)
1294                         throw new ObjectNotFoundException("No username specified");
1295
1296                 User user = dao.getUser(username);
1297                 user.setName(name);
1298                 user.setEmail(mail);
1299                 return user;
1300         }
1301
1302         @Override
1303         public User findUser(String username) {
1304                 if (username == null)
1305                         return null;
1306                 return dao.findUser(username);
1307         }
1308
1309         @Override
1310         public User updateUserToken(Long userId) throws ObjectNotFoundException {
1311                 if (userId == null)
1312                         throw new ObjectNotFoundException("No user specified");
1313                 User user = dao.getEntityById(User.class, userId);
1314                 user.generateAuthToken();
1315                 return user;
1316         }
1317
1318         /* (non-Javadoc)
1319          * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolderPermissions(java.lang.Long, java.lang.Long)
1320          */
1321         @Override
1322         public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1323                 if (userId == null)
1324                         throw new ObjectNotFoundException("No user specified");
1325                 if (folderId == null)
1326                         throw new ObjectNotFoundException("No folder specified");
1327                 User user = dao.getEntityById(User.class, userId);
1328                 Folder folder = dao.getEntityById(Folder.class, folderId);
1329                 if(!folder.hasReadPermission(user))
1330                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
1331                 Set<Permission> perms = folder.getPermissions();
1332                 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1333                 for (Permission perm : perms)
1334                         if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1335                                 result.add(perm.getDTO());
1336                 for (Permission perm : perms)
1337                         if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1338                         } else
1339                                 result.add(perm.getDTO());
1340                 return result;
1341
1342         }
1343
1344         /* (non-Javadoc)
1345          * @see gr.ebs.gss.server.ejb.ExternalAPI#setFolderPermissions(java.lang.Long, java.lang.Long, java.util.Set)
1346          */
1347         @Override
1348         public void setFolderPermissions(Long userId, Long folderId, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1349                 if (userId == null)
1350                         throw new ObjectNotFoundException("No user specified");
1351                 if (folderId == null)
1352                         throw new ObjectNotFoundException("No folder specified");
1353                 User user = dao.getEntityById(User.class, userId);
1354                 Folder folder = dao.getEntityById(Folder.class, folderId);
1355                 if(!folder.hasModifyACLPermission(user))
1356                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
1357                 folder.getPermissions().clear();
1358                 for (PermissionDTO dto : permissions)
1359                         folder.addPermission(getPermission(dto));
1360                 dao.update(folder);
1361                 for (FileHeader fh : folder.getFiles())
1362                         setFilePermissions(userId, fh.getId(), fh.isReadForAll(), permissions);
1363                 for (Folder sub : folder.getSubfolders())
1364                         setFolderPermissions(userId, sub.getId(), permissions);
1365         }
1366
1367         private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1368                 Permission res = new Permission();
1369                 if (dto.getGroup() != null)
1370                         res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1371                 else if (dto.getUser() != null)
1372                         if (dto.getUser().getId() == null)
1373                                 res.setUser(dao.getUser(dto.getUser().getUsername()));
1374                         else
1375                                 res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1376                 res.setRead(dto.hasRead());
1377                 res.setWrite(dto.hasWrite());
1378                 res.setModifyACL(dto.hasModifyACL());
1379                 return res;
1380         }
1381
1382         /* (non-Javadoc)
1383          * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1384          */
1385         @Override
1386         public List<UserDTO> getUsersByUserNameLike(String username) {
1387                 List<User> users = dao.getUsersByUserNameLike(username);
1388                 List<UserDTO> result = new ArrayList<UserDTO>();
1389                 for (User u : users)
1390                         result.add(u.getDTO());
1391                 return result;
1392
1393         }
1394
1395         /* (non-Javadoc)
1396          * @see gr.ebs.gss.server.ejb.ExternalAPI#addUserToGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1397          */
1398         @Override
1399         public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1400                 if (userId == null)
1401                         throw new ObjectNotFoundException("No user specified");
1402                 if (groupId == null)
1403                         throw new ObjectNotFoundException("No group specified");
1404                 if (userToAddId == null)
1405                         throw new ObjectNotFoundException("No user to add specified");
1406                 User user = dao.getEntityById(User.class, userId);
1407                 Group group = dao.getEntityById(Group.class, groupId);
1408                 if (!group.getOwner().equals(user))
1409                         throw new InsufficientPermissionsException();
1410                 User userToAdd = dao.getEntityById(User.class, userToAddId);
1411                 if (group.contains(userToAdd))
1412                         throw new DuplicateNameException("User already exists in group");
1413                 group.getMembers().add(userToAdd);
1414                 dao.update(group);
1415
1416         }
1417
1418         @Override
1419         public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1420                 if (userId == null)
1421                         throw new ObjectNotFoundException("No user specified");
1422                 User user = dao.getEntityById(User.class, userId);
1423                 user.invalidateAuthToken();
1424                 return;
1425         }
1426
1427         @Override
1428         public List<FolderDTO> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1429                 if (userId == null)
1430                         throw new ObjectNotFoundException("No user specified");
1431                 List<Folder> folders = dao.getSharedRootFolders(userId);
1432                 List<FolderDTO> result = new ArrayList<FolderDTO>();
1433                 for (Folder f : folders) {
1434                         FolderDTO dto = f.getDTO();
1435                         dto.setSubfolders(getSharedSubfolders(userId, f.getId()));
1436                         result.add(dto);
1437                 }
1438                 return result;
1439         }
1440
1441         /* (non-Javadoc)
1442          * @see gr.ebs.gss.server.ejb.ExternalAPI#removeMemberFromGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1443          */
1444         @Override
1445         public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1446                 if (userId == null)
1447                         throw new ObjectNotFoundException("No user specified");
1448                 if (groupId == null)
1449                         throw new ObjectNotFoundException("No group specified");
1450                 if (memberId == null)
1451                         throw new ObjectNotFoundException("No member specified");
1452                 User owner = dao.getEntityById(User.class, userId);
1453                 Group group = dao.getEntityById(Group.class, groupId);
1454                 User member = dao.getEntityById(User.class, memberId);
1455                 if (!group.getOwner().equals(owner))
1456                         throw new InsufficientPermissionsException("User is not the owner of the group");
1457                 group.removeMemberFromGroup(member);
1458                 dao.update(group);
1459
1460         }
1461
1462         /* (non-Javadoc)
1463          * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersSharingFoldersForUser(java.lang.Long)
1464          */
1465         @Override
1466         public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1467                 List<User> users = dao.getUsersSharingFoldersForUser(userId);
1468                 List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1469                 List<UserDTO> res = new ArrayList<UserDTO>();
1470                 for (User u : users)
1471                         res.add(u.getDTO());
1472                 for(User fu : usersFiles)
1473                         if(!users.contains(fu))
1474                                 res.add(fu.getDTO());
1475                 return res;
1476         }
1477
1478         /* (non-Javadoc)
1479          * @see gr.ebs.gss.server.ejb.ExternalAPI#getFilePermissions(java.lang.Long, java.lang.Long)
1480          */
1481         @Override
1482         public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1483                 if (userId == null)
1484                         throw new ObjectNotFoundException("No user specified");
1485                 if (fileId == null)
1486                         throw new ObjectNotFoundException("No folder specified");
1487                 User user = dao.getEntityById(User.class, userId);
1488                 FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1489                 if(!folder.hasReadPermission(user))
1490                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
1491                 Set<Permission> perms = folder.getPermissions();
1492                 Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1493                 for (Permission perm : perms)
1494                         if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1495                                 result.add(perm.getDTO());
1496                 for (Permission perm : perms)
1497                         if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1498                         } else
1499                                 result.add(perm.getDTO());
1500                 return result;
1501         }
1502
1503         @Override
1504         public void setFilePermissions(Long userId, Long fileId, Boolean readForAll, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1505                 if (userId == null)
1506                         throw new ObjectNotFoundException("No user specified");
1507                 if (fileId == null)
1508                         throw new ObjectNotFoundException("No folder specified");
1509
1510                 User user = dao.getEntityById(User.class, userId);
1511                 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1512                 if(!file.hasModifyACLPermission(user))
1513                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
1514
1515                 if (readForAll != null)
1516                         if (user.equals(file.getOwner()))
1517                                 file.setReadForAll(readForAll);
1518                         else
1519                                 throw new InsufficientPermissionsException("Only the owner can change the read-for-all flag");
1520
1521                 if (permissions != null && !permissions.isEmpty()) {
1522                         file.getPermissions().clear();
1523                         for (PermissionDTO dto : permissions)
1524                                 file.addPermission(getPermission(dto));
1525                 }
1526
1527                 // Update the file if there was a change.
1528                 if (readForAll != null || permissions != null && !permissions.isEmpty())
1529                         dao.update(file);
1530
1531         }
1532
1533         @Override
1534         public List<FileHeaderDTO> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1535                 if (userId == null)
1536                         throw new ObjectNotFoundException("No user specified");
1537                 List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1538                 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1539                 for (FileHeader f : files)
1540                         result.add(f.getDTO());
1541                 return result;
1542         }
1543
1544         @Override
1545         public List<FileHeaderDTO> getSharedFiles(Long userId) throws ObjectNotFoundException {
1546                 if (userId == null)
1547                         throw new ObjectNotFoundException("No user specified");
1548                 List<FileHeader> files = dao.getSharedFiles(userId);
1549                 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1550                 for (FileHeader f : files)
1551                         result.add(f.getDTO());
1552                 return result;
1553         }
1554
1555         @Override
1556         public List<FolderDTO> getSharedFolders(Long userId) throws ObjectNotFoundException {
1557                 if (userId == null)
1558                         throw new ObjectNotFoundException("No user specified");
1559                 List<Folder> folders = dao.getSharedFolders(userId);
1560                 List<FolderDTO> result = new ArrayList<FolderDTO>();
1561                 for (Folder f : folders)
1562                         result.add(f.getDTO());
1563                 return result;
1564         }
1565
1566         /* (non-Javadoc)
1567          * @see gr.ebs.gss.server.ejb.ExternalAPI#getSharedFiles(java.lang.Long, java.lang.Long)
1568          */
1569         @Override
1570         public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1571                 if (ownerId == null)
1572                         throw new ObjectNotFoundException("No owner specified");
1573                 if (callingUserId == null)
1574                         throw new ObjectNotFoundException("No calling user specified");
1575                 List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1576                 List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1577                 for (FileHeader f : folders)
1578                         result.add(f.getDTO());
1579                 return result;
1580         }
1581
1582         @Override
1583         public List<FolderDTO> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1584                 if (ownerId == null)
1585                         throw new ObjectNotFoundException("No owner specified");
1586                 if (callingUserId == null)
1587                         throw new ObjectNotFoundException("No calling user specified");
1588                 List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1589                 List<FolderDTO> result = new ArrayList<FolderDTO>();
1590                 for (Folder f : folders) {
1591                         FolderDTO dto = f.getDTO();
1592                         dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1593                         result.add(dto);
1594                 }
1595                 return result;
1596
1597         }
1598
1599         @Override
1600         public List<FolderDTO> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1601                 if (userId == null)
1602                         throw new ObjectNotFoundException("No user specified");
1603                 if (folderId == null)
1604                         throw new ObjectNotFoundException("No folder specified");
1605                 User user = dao.getEntityById(User.class, userId);
1606                 Folder folder = dao.getEntityById(Folder.class, folderId);
1607                 List<FolderDTO> result = new ArrayList<FolderDTO>();
1608                 if (folder.isShared(user))
1609                         for (Folder f : folder.getSubfolders())
1610                                 if (f.isShared(user) && !f.isDeleted())
1611                                         result.add(f.getDTO());
1612                 return result;
1613         }
1614
1615         @Override
1616         public List<FolderDTO> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1617                 if (userId == null)
1618                         throw new ObjectNotFoundException("No user specified");
1619                 if (callingUserId == null)
1620                         throw new ObjectNotFoundException("No user specified");
1621                 if (folderId == null)
1622                         throw new ObjectNotFoundException("No folder specified");
1623                 User user = dao.getEntityById(User.class, callingUserId);
1624                 Folder folder = dao.getEntityById(Folder.class, folderId);
1625                 List<FolderDTO> result = new ArrayList<FolderDTO>();
1626                 if (folder.isSharedForOtherUser(user))
1627                         for (Folder f : folder.getSubfolders())
1628                                 if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1629                                         FolderDTO dto = f.getDTO();
1630                                         dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId()));
1631                                         result.add(dto);
1632                                 }
1633                 return result;
1634
1635         }
1636
1637         /* (non-Javadoc)
1638          * @see gr.ebs.gss.server.ejb.ExternalAPI#searchFiles(java.lang.Long, java.lang.String)
1639          */
1640         @Override
1641         public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1642                 if (userId == null)
1643                         throw new ObjectNotFoundException("No user specified");
1644                 User user = getUser(userId);
1645                 if (query == null)
1646                         throw new ObjectNotFoundException("No query specified");
1647                 List<FileHeader> files = search(user.getId(), query);
1648                 List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1649                 for(FileHeader f : files)
1650                         res.add(f.getDTO());
1651                 return res;
1652         }
1653
1654         /**
1655          * Performs the actuals search on the solr server and returns the results
1656          *
1657          * We have to use the dismax query type (instead of the
1658          * standard) because it allows for search time field boosting. This is because we can't use indexing
1659          * time field boosting due to the patched rich indexing API that does not allow it
1660          *
1661          * @param userId
1662          * @param query
1663          * @return a List of FileHeader objects
1664          */
1665         private List<FileHeader> search(Long userId, String query) {
1666                 try {
1667                         HttpClient httpClient = new HttpClient();
1668
1669                         GetMethod method = new GetMethod(conf.getString("solrSelectUrl"));
1670                         NameValuePair[] params = {new NameValuePair("qt", "dismax"),
1671                                                                                 new NameValuePair("q", query),
1672                                                                                 new NameValuePair("sort", "score desc"),
1673                                                                                 new NameValuePair("indent", "on")};
1674                         method.setQueryString(params);
1675                         int retryCount = 0;
1676                         int statusCode = 0;
1677                         String response = null;
1678                         do {
1679                                 statusCode = httpClient.executeMethod(method);
1680                                 logger.debug("HTTP status: " + statusCode);
1681                                 response = method.getResponseBodyAsString();
1682                                 logger.debug(response);
1683                                 retryCount++;
1684                                 if (statusCode != 200 && retryCount < 3)
1685                                         try {
1686                                                 Thread.sleep(3000); //Give Solr a little time to be available
1687                                         } catch (InterruptedException e) {
1688                                         }
1689                         } while (statusCode != 200 && retryCount < 3);
1690                         if (statusCode != 200)
1691                                 throw new EJBException("Search query return error:\n" + response);
1692
1693                         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1694                         DocumentBuilder db = dbf.newDocumentBuilder();
1695                         Document doc = db.parse(method.getResponseBodyAsStream());
1696                         method.releaseConnection();
1697
1698                         Node root = doc.getElementsByTagName("response").item(0);
1699                         Node lst = root.getFirstChild().getNextSibling();
1700                         Node status = lst.getFirstChild().getNextSibling();
1701                         if (status.getAttributes().getNamedItem("name").getNodeValue().equals("status") &&
1702                                 status.getTextContent().equals("0")) {
1703                                 List<FileHeader> fileResult = new ArrayList<FileHeader>();
1704                                 Node result = lst.getNextSibling().getNextSibling();
1705                                 NodeList docs = result.getChildNodes();
1706                                 User user = getUser(userId);
1707                                 for (int i=1; i<docs.getLength(); i=i+2) {
1708                                         Node d = docs.item(i);
1709                                         NodeList docData = d.getChildNodes();
1710                                         for (int j=1; j<docData.getLength(); j=j+2) {
1711                                                 Node dd = docData.item(j);
1712                                                 if (dd.getAttributes().item(0).getNodeName().equals("name") &&
1713                                                         dd.getAttributes().item(0).getNodeValue().equals("id")) {
1714                                                         Long fileId = Long.valueOf(dd.getTextContent());
1715                                                         try {
1716                                                                 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1717                                                                 if (file.hasReadPermission(user)) {
1718                                                                         fileResult.add(file);
1719                                                                         logger.debug("File added " + fileId);
1720                                                                 }
1721                                                         } catch (ObjectNotFoundException e) {
1722                                                                 logger.warn("Search result not found", e);
1723                                                         }
1724                                                 }
1725                                         }
1726                                 }
1727                                 return fileResult;
1728                         }
1729                         throw new EJBException();
1730                 } catch (HttpException e) {
1731                         throw new EJBException(e);
1732                 } catch (IOException e) {
1733                         throw new EJBException(e);
1734                 } catch (SAXException e) {
1735                         throw new EJBException(e);
1736                 } catch (ParserConfigurationException e) {
1737                         throw new EJBException(e);
1738                 } catch (ObjectNotFoundException e) {
1739                         throw new EJBException(e);
1740                 }
1741         }
1742
1743         /* (non-Javadoc)
1744          * @see gr.ebs.gss.server.ejb.ExternalAPI#copyFiles(java.lang.Long, java.util.List, java.lang.Long)
1745          */
1746         @Override
1747         public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1748                 for(Long l : fileIds){
1749                         FileHeader file = dao.getEntityById(FileHeader.class, l);
1750                         copyFile(userId, l, destId, file.getName());
1751                 }
1752
1753
1754         }
1755
1756         /* (non-Javadoc)
1757          * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFiles(java.lang.Long, java.util.List, java.lang.Long)
1758          */
1759         @Override
1760         public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, DuplicateNameException, GSSIOException, QuotaExceededException {
1761                 for(Long l : fileIds){
1762                         FileHeader file = dao.getEntityById(FileHeader.class, l);
1763                         moveFile(userId, l, destId, file.getName());
1764                 }
1765
1766         }
1767
1768         /* (non-Javadoc)
1769          * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFiles(java.lang.Long, java.util.List)
1770          */
1771         @Override
1772         public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1773                 if (userId == null)
1774                         throw new ObjectNotFoundException("No user specified");
1775                 final User user = dao.getEntityById(User.class, userId);
1776                 List<File> filesToRemove = new ArrayList<File>();
1777                 //first delete database objects
1778                 for(Long fileId : fileIds){
1779                         if (fileId == null)
1780                                 throw new ObjectNotFoundException("No file specified");
1781                         final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1782                         final Folder parent = file.getFolder();
1783                         if (parent == null)
1784                                 throw new ObjectNotFoundException("The specified file has no parent folder");
1785                         if (!file.hasDeletePermission(user))
1786                                 throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1787
1788                         parent.removeFile(file);
1789                         for (final FileBody body : file.getBodies()) {
1790                                 final File fileContents = new File(body.getStoredFilePath());
1791                                 filesToRemove.add(fileContents);
1792                         }
1793                         dao.delete(file);
1794                 }
1795                 //then remove physical files if everything is ok
1796                 for(File physicalFile : filesToRemove)
1797                         if (!physicalFile.delete())
1798                                 logger.error("Could not delete file " + physicalFile.getPath());
1799                 //then unindex deleted files
1800                 for(Long fileId : fileIds)
1801                         indexFile(fileId, true);
1802
1803         }
1804
1805         /* (non-Javadoc)
1806          * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFilesToTrash(java.lang.Long, java.util.List)
1807          */
1808         @Override
1809         public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1810                 for(Long l : fileIds)
1811                         moveFileToTrash(userId, l);
1812
1813         }
1814
1815         @Override
1816         public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1817                 for(Long l : fileIds)
1818                         removeFileFromTrash(userId, l);
1819
1820         }
1821
1822         @Override
1823         public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1824                 if (userId == null)
1825                         throw new ObjectNotFoundException("No user specified");
1826                 User user = dao.getEntityById(User.class, userId);
1827                 Nonce nonce = Nonce.createNonce(user.getId());
1828                 dao.create(nonce);
1829                 return nonce;
1830         }
1831
1832         @Override
1833         public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1834                 if (userId == null)
1835                         throw new ObjectNotFoundException("No user specified");
1836                 if (nonce == null)
1837                         throw new ObjectNotFoundException("No nonce specified");
1838                 return dao.getNonce(nonce, userId);
1839         }
1840
1841         @Override
1842         public void removeNonce(Long id) throws ObjectNotFoundException {
1843                 if (id == null)
1844                         throw new ObjectNotFoundException("No nonce specified");
1845                 Nonce nonce = dao.getEntityById(Nonce.class, id);
1846                 dao.delete(nonce);
1847         }
1848
1849         @Override
1850         public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1851                 if (userId == null)
1852                         throw new ObjectNotFoundException("No user specified");
1853                 User user = dao.getEntityById(User.class, userId);
1854                 user.setNonce(nonce);
1855                 user.setNonceExpiryDate(nonceExpiryDate);
1856         }
1857
1858         /* (non-Javadoc)
1859          * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserStatistics(java.lang.Long)
1860          */
1861         @Override
1862         public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1863                 if (userId == null)
1864                         throw new ObjectNotFoundException("No user specified");
1865                 StatsDTO stats = new StatsDTO();
1866                 stats.setFileCount(dao.getFileCount(userId));
1867                 Long fileSize = dao.getFileSize(userId);
1868                 stats.setFileSize(fileSize);
1869                 Long quota = conf.getLong("quota", new Long(52428800L));
1870                 Long quotaLeft = quota - fileSize;
1871                 stats.setQuotaLeftSize(quotaLeft);
1872                 return stats;
1873         }
1874
1875         /* (non-Javadoc)
1876          * @see gr.ebs.gss.server.ejb.ExternalAPI#getVersions(java.lang.Long, java.lang.Long)
1877          */
1878         @Override
1879         public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1880                 if (userId == null)
1881                         throw new ObjectNotFoundException("No user specified");
1882                 if (fileId == null)
1883                         throw new ObjectNotFoundException("No file specified");
1884                 User user = dao.getEntityById(User.class, userId);
1885                 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1886                 if(!header.hasReadPermission(user))
1887                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
1888                 List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
1889                 for(int i = header.getBodies().size()-1 ; i>=0; i--)
1890                         result.add(header.getBodies().get(i).getDTO());
1891                 return result;
1892         }
1893
1894         /* (non-Javadoc)
1895          * @see gr.ebs.gss.server.ejb.ExternalAPI#removeVersion(java.lang.Long, java.lang.Long, java.lang.Long)
1896          */
1897         @Override
1898         public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
1899                 if (userId == null)
1900                         throw new ObjectNotFoundException("No user specified");
1901                 if (fileId == null)
1902                         throw new ObjectNotFoundException("No file specified");
1903                 if (bodyId == null)
1904                         throw new ObjectNotFoundException("No body specified");
1905                 User user = dao.getEntityById(User.class, userId);
1906                 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1907                 if(!header.hasWritePermission(user))
1908                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
1909                 FileBody body = dao.getEntityById(FileBody.class, bodyId);
1910                 if(body.equals(header.getCurrentBody())){
1911
1912                         if(header.getBodies().size() == 1)
1913                                 throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
1914                         for(FileBody b : header.getBodies())
1915                                 if(b.getVersion() == body.getVersion()-1)
1916                                         header.setCurrentBody(b);
1917                 }
1918                 final File fileContents = new File(body.getStoredFilePath());
1919                 if (!fileContents.delete())
1920                         logger.error("Could not delete file " + body.getStoredFilePath());
1921                 header.getBodies().remove(body);
1922
1923
1924         }
1925
1926         @Override
1927         public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException,  GSSIOException, QuotaExceededException {
1928                 if (userId == null)
1929                         throw new ObjectNotFoundException("No user specified");
1930                 if (fileId == null)
1931                         throw new ObjectNotFoundException("No file specified");
1932                 User user = dao.getEntityById(User.class, userId);
1933                 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1934                 if(!header.hasWritePermission(user))
1935                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
1936                 FileBody body = dao.getFileVersion(fileId, version);
1937                 final File fileContents = new File(body.getStoredFilePath());
1938
1939                 try {
1940                         updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
1941                 } catch (FileNotFoundException e) {
1942                         throw new GSSIOException(e);
1943                 }
1944
1945         }
1946
1947         /* (non-Javadoc)
1948          * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
1949          */
1950         @Override
1951         public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1952                 if (userId == null)
1953                         throw new ObjectNotFoundException("No user specified");
1954                 if (fileId == null)
1955                         throw new ObjectNotFoundException("No file specified");
1956                 User user = dao.getEntityById(User.class, userId);
1957                 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1958                 if(!header.hasWritePermission(user))
1959                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
1960                 Iterator<FileBody> it = header.getBodies().iterator();
1961                 while(it.hasNext()){
1962                         FileBody body = it.next();
1963                         if(!body.equals(header.getCurrentBody())){
1964                                 final File fileContents = new File(body.getStoredFilePath());
1965                                 if (!fileContents.delete())
1966                                         logger.error("Could not delete file " + body.getStoredFilePath());
1967                                 it.remove();
1968                                 dao.delete(body);
1969                         }
1970                 }
1971                 header.getCurrentBody().setVersion(1);
1972
1973         }
1974
1975         /* (non-Javadoc)
1976          * @see gr.ebs.gss.server.ejb.ExternalAPI#toggleFileVersioning(java.lang.Long, java.lang.Long, boolean)
1977          */
1978         @Override
1979         public void toggleFileVersioning(Long userId, Long fileId, boolean versioned) throws ObjectNotFoundException, InsufficientPermissionsException {
1980                 if (userId == null)
1981                         throw new ObjectNotFoundException("No user specified");
1982                 if (fileId == null)
1983                         throw new ObjectNotFoundException("No file specified");
1984                 User user = dao.getEntityById(User.class, userId);
1985                 FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1986                 if(!header.hasWritePermission(user))
1987                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
1988                 if(!header.isVersioned() == versioned){
1989                         if(header.isVersioned())
1990                                 removeOldVersions(userId, fileId);
1991                         header.setVersioned(versioned);
1992
1993                 }
1994         }
1995
1996         /**
1997          * Gets the quota left for specified userId
1998          * @param userId
1999          * @return
2000          */
2001         private Long getQuotaLeft(Long userId){
2002                 Long fileSize = dao.getFileSize(userId);
2003                 Long quota = conf.getLong("quota", new Long(52428800L));
2004                 return quota - fileSize;
2005         }
2006
2007         public void rebuildSolrIndex() {
2008                 MessageProducer sender = null;
2009                 Session session = null;
2010                 Connection qConn = null;
2011                 try {
2012                         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2013                         DocumentBuilder db = dbf.newDocumentBuilder();
2014                         Document doc = db.newDocument();
2015                         Node root = doc.createElement("delete");
2016                         doc.appendChild(root);
2017                         Node queryNode = doc.createElement("query");
2018                         root.appendChild(queryNode);
2019                         queryNode.appendChild(doc.createTextNode("*:*"));
2020
2021                         TransformerFactory fact = TransformerFactory.newInstance();
2022                         Transformer trans = fact.newTransformer();
2023                         trans.setOutputProperty(OutputKeys.INDENT, "yes");
2024                         StringWriter sw = new StringWriter();
2025                         StreamResult sr = new StreamResult(sw);
2026                         DOMSource source = new DOMSource(doc);
2027                         trans.transform(source, sr);
2028                         logger.debug(sw.toString());
2029
2030                         HttpClient httpClient = new HttpClient();
2031                         PostMethod method = new PostMethod(conf.getString("solrUpdateUrl"));
2032                         method.setRequestEntity(new StringRequestEntity(sw.toString()));
2033                         int retryCount = 0;
2034                         int statusCode = 0;
2035                         String response = null;
2036                         do {
2037                                 statusCode = httpClient.executeMethod(method);
2038                                 logger.debug("HTTP status: " + statusCode);
2039                                 response = method.getResponseBodyAsString();
2040                                 logger.debug(response);
2041                                 retryCount++;
2042                                 if (statusCode != 200 && retryCount < 3)
2043                                         try {
2044                                                 Thread.sleep(10000); //Give Solr a little time to be available
2045                                         } catch (InterruptedException e) {
2046                                         }
2047                         } while (statusCode != 200 && retryCount < 3);
2048                         method.releaseConnection();
2049                         if (statusCode != 200)
2050                                 throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response);
2051                         List<Long> fileIds = dao.getAllFileIds();
2052
2053                         Context jndiCtx = new InitialContext();
2054                         ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
2055                         Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
2056                         qConn = factory.createConnection();
2057                         session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
2058                         sender = session.createProducer(queue);
2059
2060                         for (Long id : fileIds) {
2061                                 MapMessage map = session.createMapMessage();
2062                                 map.setObject("id", id);
2063                                 map.setBoolean("delete", false);
2064                                 sender.send(map);
2065                         }
2066                         sendOptimize(httpClient, 0);
2067                 } catch (DOMException e) {
2068                         throw new EJBException(e);
2069                 } catch (TransformerConfigurationException e) {
2070                         throw new EJBException(e);
2071                 } catch (IllegalArgumentException e) {
2072                         throw new EJBException(e);
2073                 } catch (HttpException e) {
2074                         throw new EJBException(e);
2075                 } catch (UnsupportedEncodingException e) {
2076                         throw new EJBException(e);
2077                 } catch (ParserConfigurationException e) {
2078                         throw new EJBException(e);
2079                 } catch (TransformerException e) {
2080                         throw new EJBException(e);
2081                 } catch (IOException e) {
2082                         throw new EJBException(e);
2083                 } catch (NamingException e) {
2084                         throw new EJBException(e);
2085                 } catch (JMSException e) {
2086                         throw new EJBException(e);
2087                 }
2088                 finally {
2089                         try {
2090                                 if (sender != null)
2091                                         sender.close();
2092                                 if (session != null)
2093                                         session.close();
2094                                 if (qConn != null)
2095                                         qConn.close();
2096                         }
2097                         catch (JMSException e) {
2098                                 logger.warn(e);
2099                         }
2100                 }
2101         }
2102
2103         /**
2104          * Sends a optimize message to the solr server
2105          *
2106          * @param httpClient
2107          * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive
2108          *                                      calls to stop the recursion
2109          * @throws UnsupportedEncodingException
2110          * @throws IOException
2111          * @throws HttpException
2112          */
2113         private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException {
2114                 PostMethod method = null;
2115                 try {
2116                         logger.debug("Optimize retry: " + retryCount);
2117                         method = new PostMethod(conf.getString("solrUpdateUrl"));
2118                         method.setRequestEntity(new StringRequestEntity("<optimize/>", "text/xml", "iso8859-1"));
2119                         int statusCode = httpClient.executeMethod(method);
2120                         logger.debug("HTTP status: " + statusCode);
2121                         String response = method.getResponseBodyAsString();
2122                         logger.debug(response);
2123                         if (statusCode != 200 && retryCount < 2) {
2124                                 try {
2125                                         Thread.sleep(10000); //Give Solr a little time to be available
2126                                 } catch (InterruptedException e) {
2127                                 }
2128                                 sendOptimize(httpClient, retryCount + 1);
2129                         }
2130                 }
2131                 finally {
2132                         if (method != null)
2133                                 method.releaseConnection();
2134                 }
2135         }
2136
2137         public void createFile(Long userId, Long folderId, String name, String mimeType, File fileObject)
2138                         throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2139                         InsufficientPermissionsException, QuotaExceededException {
2140                 // Validate.
2141                 if (userId == null)
2142                         throw new ObjectNotFoundException("No user specified");
2143                 if (folderId == null)
2144                         throw new ObjectNotFoundException("No folder specified");
2145                 String contentType = mimeType;
2146                 if (StringUtils.isEmpty(mimeType))
2147                         contentType = DEFAULT_MIME_TYPE;
2148                 if (StringUtils.isEmpty(name))
2149                         throw new ObjectNotFoundException("No file name specified");
2150                 if (dao.existsFolderOrFile(folderId, name))
2151                         throw new DuplicateNameException("A folder or file with the name '" + name +
2152                                                 "' already exists at this level");
2153
2154                 // Do the actual work.
2155                 Folder parent = null;
2156                 try {
2157                         parent = dao.getEntityById(Folder.class, folderId);
2158                 } catch (final ObjectNotFoundException onfe) {
2159                         // Supply a more accurate problem description.
2160                         throw new ObjectNotFoundException("Parent folder not found");
2161                 }
2162                 final User owner = dao.getEntityById(User.class, userId);
2163                 if (!parent.hasWritePermission(owner))
2164                         throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2165                 final FileHeader file = new FileHeader();
2166                 file.setName(name);
2167                 parent.addFile(file);
2168                 // set file owner to folder owner
2169                 file.setOwner(parent.getOwner());
2170
2171                 final Date now = new Date();
2172                 final AuditInfo auditInfo = new AuditInfo();
2173                 auditInfo.setCreatedBy(owner);
2174                 auditInfo.setCreationDate(now);
2175                 auditInfo.setModifiedBy(owner);
2176                 auditInfo.setModificationDate(now);
2177                 file.setAuditInfo(auditInfo);
2178                 // TODO set the proper versioning flag on creation
2179                 file.setVersioned(false);
2180
2181                 for (final Permission p : parent.getPermissions()) {
2182                         final Permission permission = new Permission();
2183                         permission.setGroup(p.getGroup());
2184                         permission.setUser(p.getUser());
2185                         permission.setRead(p.getRead());
2186                         permission.setWrite(p.getWrite());
2187                         permission.setModifyACL(p.getModifyACL());
2188                         file.addPermission(permission);
2189                 }
2190
2191                 // Create the file body.
2192                 try {
2193                         createFileBody(name, contentType, fileObject, file, auditInfo, owner);
2194                 } catch (FileNotFoundException e) {
2195                         throw new GSSIOException(e);
2196                 }
2197                 dao.flush();
2198                 indexFile(file.getId(), false);
2199         }
2200
2201         /* (non-Javadoc)
2202          * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFileContents(java.lang.Long, java.lang.Long, java.lang.String, java.io.InputStream)
2203          */
2204         public void updateFileContents(Long userId, Long fileId, String mimeType, File fileObject) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2205                 if (userId == null)
2206                         throw new ObjectNotFoundException("No user specified");
2207                 if (fileId == null)
2208                         throw new ObjectNotFoundException("No file specified");
2209                 String contentType = mimeType;
2210
2211                 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2212
2213                 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2214                 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType))
2215                         contentType = identifyMimeType(file.getName());
2216
2217                 final User owner = dao.getEntityById(User.class, userId);
2218                 if (!file.hasWritePermission(owner))
2219                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
2220                 final Date now = new Date();
2221                 final AuditInfo auditInfo = new AuditInfo();
2222                 auditInfo.setCreatedBy(owner);
2223                 auditInfo.setCreationDate(now);
2224                 auditInfo.setModifiedBy(owner);
2225                 auditInfo.setModificationDate(now);
2226                 try {
2227                         createFileBody(file.getName(), contentType, fileObject, file, auditInfo, owner);
2228                 } catch (FileNotFoundException e) {
2229                         throw new GSSIOException(e);
2230                 }
2231
2232                 indexFile(fileId, false);
2233         }
2234
2235         /**
2236          * Helper method for identifying mime type by examining the filename extension
2237          *
2238          * @param filename
2239          * @return the mime type
2240          */
2241         private String identifyMimeType(String filename) {
2242                 if (filename.indexOf('.') != 1) {
2243                         String extension = filename.substring(filename.lastIndexOf('.'));
2244                         if (".doc".equals(extension))
2245                                 return "application/msword";
2246                         else if (".xls".equals(extension))
2247                                 return "application/vnd.ms-excel";
2248                         else if (".ppt".equals(extension))
2249                                 return "application/vnd.ms-powerpoint";
2250                         else if (".pdf".equals(extension))
2251                                 return "application/pdf";
2252                 }
2253                 // when all else fails assign the default mime type
2254                 return DEFAULT_MIME_TYPE;
2255         }
2256
2257         /**
2258          * Helper method to create a new file body and attach it as the current body
2259          * of the provided file header.
2260          *
2261          * @param name the original file name
2262          * @param mimeType the content type
2263          * @param uploadedFile the uploaded file contents
2264          * @param header the file header that will be associated with the new body
2265          * @param auditInfo the audit info
2266          * @param owner the owner of the file
2267          * @throws FileNotFoundException
2268          * @throws QuotaExceededException
2269          */
2270         private void createFileBody(String name, String mimeType, File uploadedFile,
2271                                 FileHeader header, AuditInfo auditInfo, User owner)
2272                         throws FileNotFoundException, QuotaExceededException {
2273                 FileBody body = new FileBody();
2274
2275                 // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2276                 if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType))
2277                         body.setMimeType(identifyMimeType(name));
2278                 else
2279                         body.setMimeType(mimeType);
2280                 body.setAuditInfo(auditInfo);
2281                 body.setFileSize(uploadedFile.length());
2282                 body.setOriginalFilename(name);
2283                 body.setStoredFilePath(uploadedFile.getAbsolutePath());
2284                 //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2285                 if(!header.isVersioned() && header.getCurrentBody() != null){
2286                         header.setCurrentBody(null);
2287                         if (header.getBodies() != null) {
2288                                 Iterator<FileBody> it = header.getBodies().iterator();
2289                                 while(it.hasNext()){
2290                                         FileBody bo = it.next();
2291                                         File fileContents = new File(bo.getStoredFilePath());
2292                                         if (!fileContents.delete())
2293                                                 logger.error("Could not delete file " + bo.getStoredFilePath());
2294                                         it.remove();
2295                                         dao.delete(bo);
2296                                 }
2297                         }
2298                 }
2299
2300                 Long quotaLeft = getQuotaLeft(owner.getId());
2301                 if(quotaLeft < uploadedFile.length())
2302                         throw new QuotaExceededException("Not enough free space available");
2303                 dao.flush();
2304                 header.addBody(body);
2305
2306                 dao.create(body);
2307         }
2308
2309
2310         @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2311         public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException{
2312                 if (userId == null)
2313                         throw new ObjectNotFoundException("No user specified");
2314                 User owner = dao.getEntityById(User.class, userId);
2315                 if(owner == null)
2316                         throw new ObjectNotFoundException("No user specified");
2317                 long start = 0, end = 0;
2318                 if (logger.isDebugEnabled())
2319                         start = System.currentTimeMillis();
2320                 File result = new File(generateRepositoryFilePath());
2321                 final FileOutputStream output = new FileOutputStream(result);
2322                 final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2323                 int n = 0;
2324
2325                 while (-1 != (n = stream.read(buffer)))
2326                         output.write(buffer, 0, n);
2327                 output.close();
2328                 stream.close();
2329                 if (logger.isDebugEnabled()) {
2330                         end = System.currentTimeMillis();
2331                         logger.debug("UPLOAD: "+(end-start));
2332                 }
2333                 return result;
2334         }
2335
2336
2337         public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2338
2339                 if (userId == null)
2340                         throw new ObjectNotFoundException("No user specified");
2341                 User user = dao.getEntityById(User.class, userId);
2342                 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2343                 if(status == null){
2344                         status = new FileUploadStatus();
2345                         status.setOwner(user);
2346                         status.setFilename(filename);
2347                         status.setBytesUploaded(bytesTransfered);
2348                         status.setFileSize(fileSize);
2349                         dao.create(status);
2350                 }
2351                 else{
2352                         status.setBytesUploaded(bytesTransfered);
2353                         status.setFileSize(fileSize);
2354                         dao.update(status);
2355                 }
2356
2357         }
2358
2359         public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2360                 if (userId == null)
2361                         throw new ObjectNotFoundException("No user specified");
2362                 FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2363                 if(status != null)
2364                         dao.delete(status);
2365         }
2366
2367         @Override
2368         public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2369                 return dao.getFileUploadStatus(userId, fileName);
2370         }
2371
2372         @Override
2373         public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2374                 if (userId == null)
2375                         throw new ObjectNotFoundException("No user specified");
2376                 if (folderId == null)
2377                         throw new ObjectNotFoundException("No folder specified");
2378                 final User user = dao.getEntityById(User.class, userId);
2379                 final Folder folder = dao.getEntityById(Folder.class, folderId);
2380                 // Check permissions
2381                 if (!folder.hasReadPermission(user))
2382                         throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2383                 List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2384                 if (folder.hasReadPermission(user))
2385                         for (Folder f : folder.getSubfolders())
2386                                 if (f.hasReadPermission(user) && !f.isDeleted())
2387                                         subfolders.add(f.getDTO());
2388                 FolderDTO result = folder.getDTO();
2389                 result.setSubfolders(subfolders);
2390                 return folder.getDTO();
2391         }
2392
2393         @Override
2394         public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2395                 if (userId == null)
2396                         throw new ObjectNotFoundException("No user specified");
2397                 if (folderId == null)
2398                         throw new ObjectNotFoundException("No folder specified");
2399                 User user = dao.getEntityById(User.class, callingUserId);
2400                 Folder folder = dao.getEntityById(Folder.class, folderId);
2401                 // Check permissions
2402                 if (!folder.hasReadPermission(user))
2403                         throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2404
2405                 FolderDTO result = folder.getDTO();
2406                 result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2407                 return result;
2408         }
2409
2410         @Override
2411         public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2412                         throws ObjectNotFoundException, InsufficientPermissionsException {
2413                 if (userId == null)
2414                         throw new ObjectNotFoundException("No user specified");
2415                 if (fileId == null)
2416                         throw new ObjectNotFoundException("No file specified");
2417                 if (version < 1)
2418                         throw new ObjectNotFoundException("No valid version specified");
2419                 User user = dao.getEntityById(User.class, userId);
2420                 FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2421                 if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2422                         throw new InsufficientPermissionsException("You don't have the necessary permissions");
2423                 FileBody body = dao.getFileVersion(fileId, version);
2424                 return body.getDTO();
2425         }
2426
2427         @Override
2428         public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2429                 if (userId == null)
2430                         throw new ObjectNotFoundException("No user specified");
2431                 User user = dao.getEntityById(User.class, userId);
2432                 user.setAcceptedPolicy(isAccepted);
2433                 return user;
2434         }
2435
2436 }