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