Statistics
| Branch: | Tag: | Revision:

root / src / gr / ebs / gss / server / ejb / ExternalAPIBean.java @ 01a30cd0

History | View | Annotate | Download (100.9 kB)

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.InvitationUsedException;
26
import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
27
import gr.ebs.gss.client.exceptions.QuotaExceededException;
28
import gr.ebs.gss.server.domain.AuditInfo;
29
import gr.ebs.gss.server.domain.FileBody;
30
import gr.ebs.gss.server.domain.FileHeader;
31
import gr.ebs.gss.server.domain.FileTag;
32
import gr.ebs.gss.server.domain.FileUploadStatus;
33
import gr.ebs.gss.server.domain.Folder;
34
import gr.ebs.gss.server.domain.Group;
35
import gr.ebs.gss.server.domain.Invitation;
36
import gr.ebs.gss.server.domain.Nonce;
37
import gr.ebs.gss.server.domain.Permission;
38
import gr.ebs.gss.server.domain.User;
39
import gr.ebs.gss.server.domain.UserClass;
40
import gr.ebs.gss.server.domain.dto.FileBodyDTO;
41
import gr.ebs.gss.server.domain.dto.FileHeaderDTO;
42
import gr.ebs.gss.server.domain.dto.FolderDTO;
43
import gr.ebs.gss.server.domain.dto.GroupDTO;
44
import gr.ebs.gss.server.domain.dto.PermissionDTO;
45
import gr.ebs.gss.server.domain.dto.StatsDTO;
46
import gr.ebs.gss.server.domain.dto.UserDTO;
47

    
48
import java.io.File;
49
import java.io.FileInputStream;
50
import java.io.FileNotFoundException;
51
import java.io.FileOutputStream;
52
import java.io.IOException;
53
import java.io.InputStream;
54
import java.io.StringWriter;
55
import java.io.UnsupportedEncodingException;
56
import java.util.ArrayList;
57
import java.util.Date;
58
import java.util.Iterator;
59
import java.util.LinkedHashSet;
60
import java.util.LinkedList;
61
import java.util.List;
62
import java.util.Locale;
63
import java.util.Random;
64
import java.util.Set;
65
import java.util.StringTokenizer;
66

    
67
import javax.ejb.EJB;
68
import javax.ejb.EJBException;
69
import javax.ejb.EJBTransactionRolledbackException;
70
import javax.ejb.Stateless;
71
import javax.ejb.TransactionAttribute;
72
import javax.ejb.TransactionAttributeType;
73
import javax.jms.Connection;
74
import javax.jms.ConnectionFactory;
75
import javax.jms.JMSException;
76
import javax.jms.MapMessage;
77
import javax.jms.MessageProducer;
78
import javax.jms.Queue;
79
import javax.jms.QueueConnectionFactory;
80
import javax.jms.Session;
81
import javax.naming.Context;
82
import javax.naming.InitialContext;
83
import javax.naming.NamingException;
84
import javax.persistence.PersistenceException;
85
import javax.xml.parsers.DocumentBuilder;
86
import javax.xml.parsers.DocumentBuilderFactory;
87
import javax.xml.parsers.ParserConfigurationException;
88
import javax.xml.transform.OutputKeys;
89
import javax.xml.transform.Transformer;
90
import javax.xml.transform.TransformerConfigurationException;
91
import javax.xml.transform.TransformerException;
92
import javax.xml.transform.TransformerFactory;
93
import javax.xml.transform.dom.DOMSource;
94
import javax.xml.transform.stream.StreamResult;
95

    
96
import org.apache.commons.httpclient.HttpClient;
97
import org.apache.commons.httpclient.HttpException;
98
import org.apache.commons.httpclient.NameValuePair;
99
import org.apache.commons.httpclient.methods.GetMethod;
100
import org.apache.commons.httpclient.methods.PostMethod;
101
import org.apache.commons.httpclient.methods.StringRequestEntity;
102
import org.apache.commons.lang.StringUtils;
103
import org.apache.commons.logging.Log;
104
import org.apache.commons.logging.LogFactory;
105
import org.hibernate.exception.ConstraintViolationException;
106
import org.w3c.dom.DOMException;
107
import org.w3c.dom.Document;
108
import org.w3c.dom.Node;
109
import org.w3c.dom.NodeList;
110
import org.xml.sax.SAXException;
111

    
112
import com.novell.ldap.LDAPAttribute;
113
import com.novell.ldap.LDAPAttributeSet;
114
import com.novell.ldap.LDAPConnection;
115
import com.novell.ldap.LDAPEntry;
116
import com.novell.ldap.LDAPException;
117

    
118
/**
119
 * The concrete implementation of the ExternalAPI interface.
120
 *
121
 * @author past
122
 */
123
@Stateless
124
public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
125
        /**
126
         * The default MIME type for files without an explicit one.
127
         */
128
        private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
129

    
130
        /**
131
         * The size of the buffer that is used to temporarily store chunks of
132
         * uploaded files, while storing them to the file repository.
133
         */
134
        private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
135

    
136
        /**
137
         * The logger.
138
         */
139
        private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
140

    
141
        /**
142
         * Injected reference to the GSSDAO data access facade.
143
         */
144
        @EJB
145
        private GSSDAO dao;
146

    
147

    
148
        /**
149
         * A cached random number generator for creating unique filenames.
150
         */
151
        private static Random random = new Random();
152

    
153
        /**
154
         * Mark the folder and all of its parent folders as modified from the specified user.
155
         */
156
        private void touchParentFolders(Folder folder, User user, Date date) {
157
                Folder f = folder;
158
                while (f != null) {
159
                        AuditInfo ai = f.getAuditInfo();
160
                        ai.setModifiedBy(user);
161
                        ai.setModificationDate(date);
162
                        f.setAuditInfo(ai);
163
                        f = f.getParent();
164
                }
165
        }
166

    
167
        @Override
168
        public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
169
                if (userId == null)
170
                        throw new ObjectNotFoundException("No user specified");
171
                Folder folder = dao.getRootFolder(userId);
172
                return folder.getDTO();
173
        }
174

    
175
        @Override
176
        public FolderDTO getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
177
                if (userId == null)
178
                        throw new ObjectNotFoundException("No user specified");
179
                if (folderId == null)
180
                        throw new ObjectNotFoundException("No folder specified");
181
                final User user = dao.getEntityById(User.class, userId);
182
                final Folder folder = dao.getEntityById(Folder.class, folderId);
183
                // Check permissions
184
                if (!folder.hasReadPermission(user))
185
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
186
                return folder.getDTO();
187
        }
188

    
189
        /* (non-Javadoc)
190
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUser(java.lang.Long)
191
         */
192
        public User getUser(Long userId) throws ObjectNotFoundException {
193
                if (userId == null)
194
                        throw new ObjectNotFoundException("No user specified");
195
                return dao.getEntityById(User.class, userId);
196
        }
197

    
198
        /* (non-Javadoc)
199
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserDTO(java.lang.Long)
200
         */
201
        public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
202
                return getUser(userId).getDTO();
203
        }
204

    
205
        /*
206
         * (non-Javadoc)
207
         *
208
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroup(java.lang.Long)
209
         */
210
        public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
211
                if (groupId == null)
212
                        throw new ObjectNotFoundException("No group specified");
213
                final Group group = dao.getEntityById(Group.class, groupId);
214
                return group.getDTO();
215
        }
216

    
217
        @Override
218
        public GroupDTO getGroup(Long userId, String name) throws ObjectNotFoundException {
219
                if (userId == null)
220
                        throw new ObjectNotFoundException("No user specified");
221
                if (name == null)
222
                        throw new ObjectNotFoundException("No group specified");
223
                User user = dao.getEntityById(User.class, userId);
224
                List<Group> groups = user.getGroupsSpecified();
225
                for (Group group: groups)
226
                        if (group.getName().equals(name))
227
                                return group.getDTO();
228
                throw new ObjectNotFoundException("Group " + name + " not found");
229
        }
230

    
231
        /*
232
         * (non-Javadoc)
233
         *
234
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroups(java.lang.Long)
235
         */
236
        public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
237
                if (userId == null)
238
                        throw new ObjectNotFoundException("No user specified");
239
                final List<Group> groups = dao.getGroups(userId);
240
                final List<GroupDTO> result = new ArrayList<GroupDTO>();
241
                for (final Group g : groups)
242
                        result.add(g.getDTO());
243
                return result;
244
        }
245

    
246
        @Override
247
        public List<FileHeaderDTO> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
248
                        throws ObjectNotFoundException, InsufficientPermissionsException {
249
                // Validate.
250
                if (userId == null)
251
                        throw new ObjectNotFoundException("No user specified");
252
                if (folderId == null)
253
                        throw new ObjectNotFoundException("No folder specified");
254
                User user = dao.getEntityById(User.class, userId);
255
                Folder folder = dao.getEntityById(Folder.class, folderId);
256
                if (!folder.hasReadPermission(user))
257
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
258
                // Do the actual work.
259
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
260
                List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
261
                for (FileHeader f : files)
262
                        result.add(f.getDTO());
263
                return result;
264
        }
265

    
266
        /*
267
         * (non-Javadoc)
268
         *
269
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsers(java.lang.Long,
270
         *      java.lang.Long)
271
         */
272
        public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
273
                // Validate.
274
                if (userId == null)
275
                        throw new ObjectNotFoundException("No user specified");
276
                if (groupId == null)
277
                        throw new ObjectNotFoundException("No group specified");
278

    
279
                // Do the actual work.
280
                final List<User> users = dao.getUsers(groupId);
281
                final List<UserDTO> result = new ArrayList<UserDTO>();
282
                for (final User u : users)
283
                        result.add(u.getDTO());
284
                return result;
285
        }
286

    
287
        @Override
288
        public FolderDTO createFolder(Long userId, Long parentId, String name)
289
                        throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
290
                // Validate.
291
                if (userId == null)
292
                        throw new ObjectNotFoundException("No user specified");
293
                if (StringUtils.isEmpty(name))
294
                        throw new ObjectNotFoundException("New folder name is empty");
295
                if (parentId == null)
296
                        throw new ObjectNotFoundException("No parent specified");
297
                if (dao.existsFolderOrFile(parentId, name))
298
                        throw new DuplicateNameException("A folder or file with the name '" +
299
                                                name + "' already exists at this level");
300

    
301
                User creator = dao.getEntityById(User.class, userId);
302

    
303
                Folder parent = null;
304
                try {
305
                        parent = dao.getEntityById(Folder.class, parentId);
306
                } catch (ObjectNotFoundException onfe) {
307
                        // Supply a more accurate problem description.
308
                        throw new ObjectNotFoundException("Parent folder not found");
309
                }
310
                if (!parent.hasWritePermission(creator))
311
                        throw new InsufficientPermissionsException("You don't have the permissions" +
312
                                        " to write to this folder");
313

    
314
                // Do the actual work.
315
                return createFolder(name, parent, creator);
316
        }
317

    
318
        /**
319
         * Create a new folder with the provided name, parent and owner.
320
         *
321
         * @param name
322
         * @param parent
323
         * @param creator
324
         * @return the new folder
325
         */
326
        private FolderDTO createFolder(String name, Folder parent, User creator) {
327
                Folder folder = new Folder();
328
                folder.setName(name);
329
                if (parent != null) {
330
                        parent.addSubfolder(folder);
331
                        folder.setOwner(parent.getOwner());
332
                } else
333
                        folder.setOwner(creator);
334

    
335
                Date now = new Date();
336
                AuditInfo auditInfo = new AuditInfo();
337
                auditInfo.setCreatedBy(creator);
338
                auditInfo.setCreationDate(now);
339
                auditInfo.setModifiedBy(creator);
340
                auditInfo.setModificationDate(now);
341
                folder.setAuditInfo(auditInfo);
342
                touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
343

    
344
                if (parent != null)
345
                        for (Permission p : parent.getPermissions()) {
346
                                Permission permission = new Permission();
347
                                permission.setGroup(p.getGroup());
348
                                permission.setUser(p.getUser());
349
                                permission.setRead(p.getRead());
350
                                permission.setWrite(p.getWrite());
351
                                permission.setModifyACL(p.getModifyACL());
352
                                folder.addPermission(permission);
353
                        }
354
                else {
355
                        Permission permission = new Permission();
356
                        permission.setUser(creator);
357
                        permission.setRead(true);
358
                        permission.setWrite(true);
359
                        permission.setModifyACL(true);
360
                        folder.addPermission(permission);
361
                }
362
                dao.create(folder);
363
                return folder.getDTO();
364
        }
365

    
366
        /*
367
         * Deletes the given folder and all its subfolders and files
368
         * Only the permissions for top folder are checked
369
         *
370
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFolder(java.lang.Long,
371
         *      java.lang.Long)
372
         */
373
        public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
374
                // Validate.
375
                if (userId == null)
376
                        throw new ObjectNotFoundException("No user specified");
377
                if (folderId == null)
378
                        throw new ObjectNotFoundException("No folder specified");
379

    
380
                // Do the actual work.
381
                final Folder folder = dao.getEntityById(Folder.class, folderId);
382
                final Folder parent = folder.getParent();
383
                if (parent == null)
384
                        throw new ObjectNotFoundException("Deleting the root folder is not allowed");
385
                final User user = dao.getEntityById(User.class, userId);
386
                if (!folder.hasDeletePermission(user)) {
387
                        logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
388
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
389
                }
390
                removeSubfolderFiles(folder);
391
                parent.removeSubfolder(folder);
392
                dao.delete(folder);
393
                touchParentFolders(parent, user, new Date());
394
        }
395

    
396
        /**
397
         * Traverses the folder and deletes all actual files (file system)
398
         * regardless of permissions
399
         *
400
         * @param folder
401
         */
402
        private void removeSubfolderFiles(Folder folder) {
403
                //remove files for all subfolders
404
                for (Folder subfolder:folder.getSubfolders())
405
                        removeSubfolderFiles(subfolder);
406
                //remove this folder's file bodies (actual files)
407
                for (FileHeader file:folder.getFiles()) {
408
                        for (FileBody body:file.getBodies())
409
                                deleteActualFile(body.getStoredFilePath());
410
                        indexFile(file.getId(), true);
411
                }
412
        }
413

    
414
        @SuppressWarnings("unchecked")
415
        public List<FolderDTO> getSubfolders(Long userId, Long folderId)
416
                        throws ObjectNotFoundException, InsufficientPermissionsException {
417
                if (userId == null)
418
                        throw new ObjectNotFoundException("No user specified");
419
                if (folderId == null)
420
                        throw new ObjectNotFoundException("No folder specified");
421
                User user = dao.getEntityById(User.class, userId);
422
                Folder folder = dao.getEntityById(Folder.class, folderId);
423
                if (!folder.hasReadPermission(user))
424
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
425
                List<FolderDTO> result = new ArrayList<FolderDTO>();
426
                if (folder.hasReadPermission(user))
427
                        for (Folder f : folder.getSubfolders())
428
                                if (f.hasReadPermission(user) && !f.isDeleted())
429
                                        result.add(f.getDTO());
430
                return result;
431
        }
432

    
433
        @Override
434
        public FolderDTO updateFolder(Long userId, Long folderId, String folderName,
435
                                Set<PermissionDTO> permissions)
436
                        throws InsufficientPermissionsException, ObjectNotFoundException,
437
                        DuplicateNameException {
438

    
439
                // Validate.
440
                if (userId == null)
441
                        throw new ObjectNotFoundException("No user specified");
442
                if (folderId == null)
443
                        throw new ObjectNotFoundException("No folder specified");
444

    
445
                Folder folder = dao.getEntityById(Folder.class, folderId);
446
                User user = dao.getEntityById(User.class, userId);
447
                if (folderName != null && !folder.hasWritePermission(user))
448
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
449
                if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
450
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
451

    
452
                Folder parent = folder.getParent();
453
                if (folderName != null) {
454
                        if (parent != null)
455
                                if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
456
                                        throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
457

    
458
                        // Do the actual modification.
459
                        folder.setName(folderName);
460
                }
461
                if (permissions != null)
462
                        setFolderPermissions(user, folder, permissions);
463

    
464
                folder.getAuditInfo().setModificationDate(new Date());
465
                folder.getAuditInfo().setModifiedBy(user);
466
                dao.update(folder);
467
                touchParentFolders(folder, user, new Date());
468
                return folder.getDTO();
469
        }
470

    
471
        /*
472
         * (non-Javadoc)
473
         *
474
         * @see gr.ebs.gss.server.ejb.ExternalAPI#createGroup(java.lang.Long,
475
         *      java.lang.String)
476
         */
477
        public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
478
                // Validate.
479
                if (userId == null)
480
                        throw new ObjectNotFoundException("No user specified");
481
                if (StringUtils.isEmpty(name))
482
                        throw new ObjectNotFoundException("New group name is empty");
483
                if (name.indexOf('/')>=0)
484
                        throw new IllegalArgumentException("Character '/' is not allowed in group name");
485
                if (dao.existsGroup(userId, name))
486
                        throw new DuplicateNameException("A group with the name '" + name + "' already exists");
487

    
488
                // TODO: Check permissions
489

    
490
                final User owner = dao.getEntityById(User.class, userId);
491

    
492
                // Do the actual work.
493
                owner.createGroup(name);
494
        }
495

    
496
        /*
497
         * (non-Javadoc)
498
         *
499
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteGroup(java.lang.Long,
500
         *      java.lang.Long)
501
         */
502
        public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
503
                // Validate.
504
                if (userId == null)
505
                        throw new ObjectNotFoundException("No user specified");
506
                if (groupId == null)
507
                        throw new ObjectNotFoundException("No group specified");
508

    
509
                // Do the actual work.
510
                final User owner = dao.getEntityById(User.class, userId);
511
                final Group group = dao.getEntityById(Group.class, groupId);
512
                // Only delete the group if actually owned by the user.
513
                if (group.getOwner().equals(owner)) {
514
                        List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
515
                        for (Folder f : folders){
516
                                f.getPermissions().removeAll(group.getPermissions());
517
                                for(FileHeader file : f.getFiles())
518
                                        file.getPermissions().removeAll(group.getPermissions());
519
                        }
520
                        List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
521
                        for(FileHeader h : files)
522
                                h.getPermissions().removeAll(group.getPermissions());
523
                        owner.removeSpecifiedGroup(group);
524
                        dao.delete(group);
525
                }
526
                else throw new InsufficientPermissionsException("You are not the owner of this group");
527
        }
528

    
529
        @Override
530
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
531
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
532
                        InsufficientPermissionsException, QuotaExceededException {
533
                File file = null;
534
                try {
535
                        file = uploadFile(stream, userId);
536
                } catch ( IOException ioe) {
537
                        // Supply a more accurate problem description.
538
                        throw new GSSIOException("Problem creating file",ioe);
539
                }
540
                return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
541
        }
542

    
543
        /* (non-Javadoc)
544
         * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
545
         */
546
        public void indexFile(Long fileId, boolean delete) {
547
                Connection qConn = null;
548
                Session session = null;
549
                MessageProducer sender = null;
550
                try {
551
                        Context jndiCtx = new InitialContext();
552
                        ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
553
                        Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
554
                        qConn = factory.createConnection();
555
                        session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
556
                        sender = session.createProducer(queue);
557

    
558
                        MapMessage map = session.createMapMessage();
559
                        map.setObject("id", fileId);
560
                        map.setBoolean("delete", delete);
561
                        sender.send(map);
562
                }
563
                catch (NamingException e) {
564
                        logger.error("Index was not updated: ", e);
565
                }
566
                catch (JMSException e) {
567
                        logger.error("Index was not updated: ", e);
568
                }
569
                finally {
570
                        try {
571
                                if (sender != null)
572
                                        sender.close();
573
                                if (session != null)
574
                                        session.close();
575
                                if (qConn != null)
576
                                        qConn.close();
577
                        }
578
                        catch (JMSException e) {
579
                                logger.warn(e);
580
                        }
581
                }
582
        }
583

    
584

    
585

    
586
        /**
587
         * A helper method that generates a unique file path for a stored file. The
588
         * files are stored using random hash names that are distributed evenly in
589
         * a 2-level tree of subdirectories named after the first two hex characters
590
         * in the name. For example, file ab1234cd5769f will be stored in the path
591
         * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
592
         * if they don't already exist.
593
         *
594
         * @return a unique new file path
595
         */
596
        private String generateRepositoryFilePath() {
597
                String filename = Long.toHexString(random.nextLong());
598
                String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
599
                File root = new File(fileRepositoryPath);
600
                if (!root.exists())
601
                        root.mkdirs();
602
                File firstFolder = new File(root + File.separator + filename.substring(0, 1));
603
                if (!firstFolder.exists())
604
                        firstFolder.mkdir();
605
                File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
606
                if (!secondFolder.exists())
607
                        secondFolder.mkdir();
608
                return secondFolder + File.separator + filename;
609
        }
610

    
611
        /*
612
         * (non-Javadoc)
613
         *
614
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFile(java.lang.Long,
615
         *      java.lang.Long)
616
         */
617
        public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
618
                // Validate.
619
                if (userId == null)
620
                        throw new ObjectNotFoundException("No user specified");
621
                if (fileId == null)
622
                        throw new ObjectNotFoundException("No file specified");
623

    
624
                // Do the actual work.
625
                final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
626
                final Folder parent = file.getFolder();
627
                if (parent == null)
628
                        throw new ObjectNotFoundException("The specified file has no parent folder");
629
                final User user = dao.getEntityById(User.class, userId);
630
                if (!file.hasDeletePermission(user))
631
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
632
                for (final FileBody body : file.getBodies())
633
                        deleteActualFile(body.getStoredFilePath());
634
                dao.delete(file);
635
                touchParentFolders(parent, user, new Date());
636
                indexFile(fileId, true);
637
        }
638

    
639
        private void deleteActualFile(String filePath) {
640
                if (filePath == null)
641
                        return;
642
                File file = new File(filePath);
643
                if (!file.delete())
644
                        logger.error("Could not delete file " + filePath);
645
        }
646

    
647
        public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
648
                if (userId == null)
649
                        throw new ObjectNotFoundException("No user specified");
650
                if (fileHeaderId == null)
651
                        throw new ObjectNotFoundException("No file specified");
652
                if (StringUtils.isEmpty(tag))
653
                        throw new ObjectNotFoundException("Tag is empty");
654

    
655
                final User user = dao.getEntityById(User.class, userId);
656
                final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
657
                final Folder parent = fh.getFolder();
658
                if (parent == null)
659
                        throw new ObjectNotFoundException("The specified file has no parent folder");
660
                user.addTag(fh, tag);
661
                touchParentFolders(parent, user, new Date());
662
        }
663

    
664
        public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
665
                return dao.getUserTags(userId);
666
        }
667

    
668
        public void updateFile(Long userId, Long fileId, String name,
669
                                String tagSet, Date modificationDate, Boolean versioned,
670
                                Boolean readForAll,        Set<PermissionDTO> permissions)
671
                        throws DuplicateNameException, ObjectNotFoundException,        InsufficientPermissionsException {
672
                if (userId == null)
673
                        throw new ObjectNotFoundException("No user specified");
674
                if (fileId == null)
675
                        throw new ObjectNotFoundException("No file specified");
676
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
677
                final Folder parent = file.getFolder();
678
                if (parent == null)
679
                        throw new ObjectNotFoundException("The specified file has no parent folder");
680

    
681
                User user = dao.getEntityById(User.class, userId);
682
                // Check permissions for modifying the file metadata.
683
                if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
684
                        throw new InsufficientPermissionsException("User " + user.getId() +        " cannot update file " + file.getName() + "(" +        file.getId() + ")");
685
                // Check permissions for making file public.
686
                if (readForAll != null && !user.equals(file.getOwner()))
687
                                throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
688
                // Check permissions for modifying the ACL.
689
                if(permissions != null && !permissions.isEmpty() &&        !file.hasModifyACLPermission(user))
690
                        throw new InsufficientPermissionsException("User " + user.getId() +        " cannot update the permissions on file " +        file.getName() + "(" + file.getId() + ")");
691

    
692
                if (name != null) {
693
                        // Do plain check for file already exists.
694
                        // Extreme concurrency case should be caught by constraint violation later.
695
                        if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
696
                        file.setName(name);
697
                }
698

    
699
                if (modificationDate != null)
700
                        file.getAuditInfo().setModificationDate(modificationDate);
701
                else
702
                        file.getAuditInfo().setModificationDate(new Date());
703
                file.getAuditInfo().setModifiedBy(user);
704

    
705
                List<FileTag> tags = file.getFileTags();
706
                if (tagSet != null) {
707
                        Iterator<FileTag> i = tags.iterator();
708
                        while (i.hasNext()) {
709
                                FileTag tag = i.next();
710
                                i.remove();
711
                                tag.setFile(null);
712
                                user.removeTag(tag);
713
                                dao.delete(tag);
714
                        }
715
                        dao.flush();
716
                        StringTokenizer st = new StringTokenizer(tagSet, ",");
717
                        while (st.hasMoreTokens())
718
                                new FileTag(user, file, st.nextToken().trim());
719
                }
720
                if (versioned != null && !file.isVersioned() == versioned) {
721
                        if (file.isVersioned())
722
                                removeOldVersions(userId, fileId);
723
                        file.setVersioned(versioned);
724
                }
725
                if (readForAll != null && user.equals(file.getOwner()))
726
                        file.setReadForAll(readForAll);
727
                if (permissions != null && !permissions.isEmpty())
728
                        setFilePermissions(file, permissions);
729

    
730
                /*
731
                 * Force constraint violation to manifest itself here.
732
                 * This should cover extreme concurrency cases that the simple check
733
                 * above hasn't caught.
734
                 */
735
                try {
736
                        dao.flush();
737
                }
738
                catch (EJBTransactionRolledbackException e) {
739
                        Throwable cause = e.getCause();
740
                        if (cause instanceof PersistenceException && cause.getCause() instanceof ConstraintViolationException)
741
                                throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
742
                        throw e;
743
                }
744

    
745
                touchParentFolders(parent, user, new Date());
746

    
747
                // Re-index the file if it was modified.
748
                if (name != null || tagSet != null)
749
                        indexFile(fileId, false);
750
        }
751

    
752
        @Override
753
        public InputStream getFileContents(Long userId, Long fileId)
754
                        throws ObjectNotFoundException, InsufficientPermissionsException {
755
                if (userId == null)
756
                        throw new ObjectNotFoundException("No user specified");
757
                if (fileId == null)
758
                        throw new ObjectNotFoundException("No file specified");
759

    
760
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
761
                User user = dao.getEntityById(User.class, userId);
762
                if (!header.hasReadPermission(user)) {
763
                        logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
764
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
765
                }
766

    
767
                File f = new File(header.getCurrentBody().getStoredFilePath());
768
                try {
769
                        return new FileInputStream(f);
770
                } catch (FileNotFoundException e) {
771
                        logger.error("Could not locate the contents of file " + f.getAbsolutePath());
772
                        throw new ObjectNotFoundException("The file contents could not be located");
773
                }
774
        }
775

    
776
        /* (non-Javadoc)
777
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
778
         */
779
        public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
780
                if (userId == null)
781
                        throw new ObjectNotFoundException("No user specified");
782
                if (fileId == null)
783
                        throw new ObjectNotFoundException("No file specified");
784
                if (bodyId == null)
785
                        throw new ObjectNotFoundException("No file specified");
786

    
787
                final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
788
                final FileBody body = dao.getEntityById(FileBody.class, bodyId);
789
                final User user = dao.getEntityById(User.class, userId);
790
                if (!header.hasReadPermission(user)) {
791
                        logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
792
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
793
                }
794

    
795
                File f = new File(body.getStoredFilePath());
796
                try {
797
                        return new FileInputStream(f);
798
                } catch (FileNotFoundException e) {
799
                        logger.error("Could not locate the contents of file " + f.getAbsolutePath());
800
                        throw new ObjectNotFoundException("The file contents could not be located");
801
                }
802
        }
803

    
804
        @Override
805
        public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
806
                if (userId == null)
807
                        throw new ObjectNotFoundException("No user specified");
808
                if (fileId == null)
809
                        throw new ObjectNotFoundException("No file specified");
810
                final User user = dao.getEntityById(User.class, userId);
811
                final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
812
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
813
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
814
                return file.getDTO();
815
        }
816

    
817
        @Override
818
        public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
819
                if (userId == null)
820
                        throw new ObjectNotFoundException("No user specified");
821
                if (fileId == null)
822
                        throw new ObjectNotFoundException("No file specified");
823
                User user = dao.getEntityById(User.class, userId);
824
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
825
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
826
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
827
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
828
                return body.getDTO();
829
        }
830

    
831
        @Override
832
        public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
833
                        throws ObjectNotFoundException {
834
                if (ownerId == null)
835
                        throw new ObjectNotFoundException("No user specified");
836
                if (StringUtils.isEmpty(path))
837
                        throw new ObjectNotFoundException("No path specified");
838

    
839
                User owner = dao.getEntityById(User.class, ownerId);
840
                List<String> pathElements = new ArrayList<String>();
841
                StringTokenizer st = new StringTokenizer(path, "/");
842
                while (st.hasMoreTokens())
843
                        pathElements.add(st.nextToken());
844
                if (pathElements.size() < 1)
845
                        return getRootFolder(owner.getId());
846
                // Store the last element, since it requires special handling.
847
                String lastElement = pathElements.remove(pathElements.size() - 1);
848
                FolderDTO cursor = getRootFolder(owner.getId());
849
                // Traverse and verify the specified folder path.
850
                for (String pathElement : pathElements) {
851
                        cursor = getFolder(cursor.getId(), pathElement);
852
                        if (cursor.isDeleted())
853
                                throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
854
                }
855

    
856
                // Use the lastElement to retrieve the actual resource.
857
                Object resource = null;
858
                try {
859
                        FileHeaderDTO file = getFile(cursor.getId(), lastElement);
860
                        if (ignoreDeleted && file.isDeleted())
861
                                throw new ObjectNotFoundException("Resource not found");
862
                        resource = file;
863
                } catch (ObjectNotFoundException e) {
864
                        // Perhaps the requested resource is not a file, so
865
                        // check for folders as well.
866
                        FolderDTO folder = getFolder(cursor.getId(), lastElement);
867
                        if (ignoreDeleted && folder.isDeleted())
868
                                throw new ObjectNotFoundException("Resource not found");
869
                        resource = folder;
870
                }
871
                return resource;
872
        }
873

    
874
        /**
875
         * Retrieve a file for the specified user that has the specified name and
876
         * its parent folder has id equal to folderId.
877
         *
878
         * @param userId the ID of the current user
879
         * @param folderId the ID of the parent folder
880
         * @param name the name of the requested file
881
         * @return the file found
882
         * @throws ObjectNotFoundException if the specified folder or file was not
883
         *             found, with the exception message mentioning the precise
884
         *             problem
885
         */
886
        private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
887
                if (folderId == null)
888
                        throw new ObjectNotFoundException("No parent folder specified");
889
                if (StringUtils.isEmpty(name))
890
                        throw new ObjectNotFoundException("No file specified");
891

    
892
                FileHeader file = dao.getFile(folderId, name);
893
                return file.getDTO();
894
        }
895

    
896
        /**
897
         * Retrieve a folder for the specified user that has the specified name and
898
         * its parent folder has id equal to parentId.
899
         *
900
         * @param parentId the ID of the parent folder
901
         * @param name the name of the requested folder
902
         * @return the folder found
903
         * @throws ObjectNotFoundException if the specified folder or parent was not
904
         *             found, with the exception message mentioning the precise
905
         *             problem
906
         */
907
        private FolderDTO getFolder(Long parentId, String name) throws ObjectNotFoundException {
908
                if (parentId == null)
909
                        throw new ObjectNotFoundException("No parent folder specified");
910
                if (StringUtils.isEmpty(name))
911
                        throw new ObjectNotFoundException("No folder specified");
912

    
913
                Folder folder = dao.getFolder(parentId, name);
914
                return folder.getDTO();
915
        }
916

    
917
        private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
918
                File file = null;
919
                try {
920
                        file = uploadFile(resourceInputStream, userId);
921
                } catch ( IOException ioe) {
922
                        // Supply a more accurate problem description.
923
                        throw new GSSIOException("Problem creating file",ioe);
924
                }
925
                return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
926
        }
927

    
928
        @Override
929
        public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
930
                if (userId == null)
931
                        throw new ObjectNotFoundException("No user specified");
932
                if (fileId == null)
933
                        throw new ObjectNotFoundException("No file specified");
934
                if (StringUtils.isEmpty(dest))
935
                        throw new ObjectNotFoundException("No destination specified");
936

    
937
                Object destination = getResourceAtPath(userId, getParentPath(dest), true);
938
                if (!(destination instanceof FolderDTO))
939
                        throw new ObjectNotFoundException("Destination parent folder not found");
940
                FolderDTO parent = (FolderDTO) destination;
941
                copyFile(userId, fileId, parent.getId(), getLastElement(dest));
942
        }
943

    
944
        @Override
945
        public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
946
                if (userId == null)
947
                        throw new ObjectNotFoundException("No user specified");
948
                if (ownerId == null)
949
                        throw new ObjectNotFoundException("No owner specified");
950
                if (fileId == null)
951
                        throw new ObjectNotFoundException("No file specified");
952
                if (StringUtils.isEmpty(dest))
953
                        throw new ObjectNotFoundException("No destination specified");
954

    
955
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
956
                if (!(destination instanceof FolderDTO))
957
                        throw new ObjectNotFoundException("Destination parent folder not found");
958
                FolderDTO parent = (FolderDTO) destination;
959
                copyFile(userId, fileId, parent.getId(), getLastElement(dest));
960
        }
961

    
962
        @Override
963
        public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
964
                if (userId == null)
965
                        throw new ObjectNotFoundException("No user specified");
966
                if (fileId == null)
967
                        throw new ObjectNotFoundException("No file specified");
968
                if (destId == null)
969
                        throw new ObjectNotFoundException("No destination specified");
970
                if (StringUtils.isEmpty(destName))
971
                        throw new ObjectNotFoundException("No destination file name specified");
972

    
973
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
974
                Folder destination = dao.getEntityById(Folder.class, destId);
975
                User user = dao.getEntityById(User.class, userId);
976
                if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
977
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
978
                boolean versioned = file.isVersioned();
979
                int versionsNumber = file.getBodies().size();
980
                FileBody oldestBody = file.getBodies().get(0);
981
                assert oldestBody != null;
982
                File contents = new File(oldestBody.getStoredFilePath());
983
                try {
984
                        createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
985
                        FileHeader copiedFile = dao.getFile(destination.getId(), destName);
986
                        copiedFile.setVersioned(versioned);
987
                        dao.flush();
988
                        if (versionsNumber > 1)
989
                                for (int i = 1; i < versionsNumber; i++) {
990
                                        FileBody body = file.getBodies().get(i);
991
                                        assert body != null;
992
                                        contents = new File(body.getStoredFilePath());
993
                                        updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
994
                                }
995
                        List<FileTag> tags = file.getFileTags();
996
                        for (FileTag tag : tags)
997
                                createTag(userId, copiedFile.getId(), tag.getTag());
998

    
999
                } catch (FileNotFoundException e) {
1000
                        throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
1001
                }
1002

    
1003
        }
1004

    
1005
        @Override
1006
        public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1007
                if (userId == null)
1008
                        throw new ObjectNotFoundException("No user specified");
1009
                if (folderId == null)
1010
                        throw new ObjectNotFoundException("No folder specified");
1011
                if (StringUtils.isEmpty(dest))
1012
                        throw new ObjectNotFoundException("No destination specified");
1013

    
1014
                Object destination = getResourceAtPath(userId, getParentPath(dest), true);
1015
                if (!(destination instanceof FolderDTO))
1016
                        throw new ObjectNotFoundException("Destination folder not found");
1017
                FolderDTO parent = (FolderDTO) destination;
1018
                copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
1019
        }
1020

    
1021
        @Override
1022
        public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1023
                if (userId == null)
1024
                        throw new ObjectNotFoundException("No user specified");
1025
                if (folderId == null)
1026
                        throw new ObjectNotFoundException("No folder specified");
1027
                if (destId == null)
1028
                        throw new ObjectNotFoundException("No destination specified");
1029
                if (StringUtils.isEmpty(destName))
1030
                        throw new ObjectNotFoundException("No destination folder name specified");
1031
                Folder folder = dao.getEntityById(Folder.class, folderId);
1032
                Folder destination = dao.getEntityById(Folder.class, destId);
1033
                User user = dao.getEntityById(User.class, userId);
1034
                if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1035
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1036
                createFolder(user.getId(), destination.getId(), destName);
1037
        }
1038

    
1039
        @Override
1040
        public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1041
                if (userId == null)
1042
                        throw new ObjectNotFoundException("No user specified");
1043
                if (ownerId == null)
1044
                        throw new ObjectNotFoundException("No owner specified");
1045
                if (folderId == null)
1046
                        throw new ObjectNotFoundException("No folder specified");
1047
                if (StringUtils.isEmpty(dest))
1048
                        throw new ObjectNotFoundException("No destination specified");
1049

    
1050
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1051
                if (!(destination instanceof FolderDTO))
1052
                        throw new ObjectNotFoundException("Destination folder not found");
1053
                FolderDTO parent = (FolderDTO) destination;
1054
                copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1055
        }
1056

    
1057
        @Override
1058
        public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1059
                if (userId == null)
1060
                        throw new ObjectNotFoundException("No user specified");
1061
                if (folderId == null)
1062
                        throw new ObjectNotFoundException("No folder specified");
1063
                if (destId == null)
1064
                        throw new ObjectNotFoundException("No destination specified");
1065
                if (StringUtils.isEmpty(destName))
1066
                        throw new ObjectNotFoundException("No destination folder name specified");
1067

    
1068
                Folder folder = dao.getEntityById(Folder.class, folderId);
1069
                Folder destination = dao.getEntityById(Folder.class, destId);
1070
                final User user = dao.getEntityById(User.class, userId);
1071
                // XXX: quick fix need to copy only visible items to user (Source
1072
                // for bugs)
1073
                if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1074
                        return;
1075
                if(folder.isDeleted())//do not copy trashed folder and contents
1076
                        return;
1077
                if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1078
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1079
                createFolder(user.getId(), destination.getId(), destName);
1080
                Folder createdFolder = dao.getFolder(destination.getId(), destName);
1081
                List<FileHeader> files = folder.getFiles();
1082
                if (files != null)
1083
                        for (FileHeader file : files)
1084
                                if(!file.isDeleted())
1085
                                        copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1086
                List<Folder> subFolders = folder.getSubfolders();
1087
                if (subFolders != null)
1088
                        for (Folder sub : subFolders)
1089
                                if(!sub.getId().equals(createdFolder.getId()))
1090
                                        copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1091

    
1092
        }
1093

    
1094
        /**
1095
         * For a provided path, remove the last element and return the rest, that is
1096
         * the path of the parent folder.
1097
         *
1098
         * @param path the specified path
1099
         * @return the path of the parent folder
1100
         * @throws ObjectNotFoundException if the provided string contains no path
1101
         *             delimiters
1102
         */
1103
        private String getParentPath(String path) throws ObjectNotFoundException {
1104
                int lastDelimiter = path.lastIndexOf('/');
1105
                if (lastDelimiter == 0)
1106
                        return "/";
1107
                if (lastDelimiter == -1)
1108
                        // No path found.
1109
                        throw new ObjectNotFoundException("There is no parent in the path: " + path);
1110
                else if (lastDelimiter < path.length() - 1)
1111
                        // Return the part before the delimiter.
1112
                        return path.substring(0, lastDelimiter);
1113
                else {
1114
                        // Remove the trailing delimiter and then recurse.
1115
                        String strippedTrail = path.substring(0, lastDelimiter);
1116
                        return getParentPath(strippedTrail);
1117
                }
1118
        }
1119

    
1120
        /**
1121
         * Get the last element in a path that denotes the file or folder name.
1122
         *
1123
         * @param path the provided path
1124
         * @return the last element in the path
1125
         */
1126
        private String getLastElement(String path) {
1127
                int lastDelimiter = path.lastIndexOf('/');
1128
                if (lastDelimiter == -1)
1129
                        // No path found.
1130
                        return path;
1131
                else if (lastDelimiter < path.length() - 1)
1132
                        // Return the part after the delimiter.
1133
                        return path.substring(lastDelimiter + 1);
1134
                else {
1135
                        // Remove the trailing delimiter and then recurse.
1136
                        String strippedTrail = path.substring(0, lastDelimiter);
1137
                        return getLastElement(strippedTrail);
1138
                }
1139
        }
1140

    
1141
        @Override
1142
        public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1143
                if (userId == null)
1144
                        throw new ObjectNotFoundException("No user specified");
1145
                if (fileId == null)
1146
                        throw new ObjectNotFoundException("No file specified");
1147

    
1148
                // Do the actual work.
1149
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1150
                Folder parent = file.getFolder();
1151
                if (parent == null)
1152
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1153
                User user = dao.getEntityById(User.class, userId);
1154
                if (!file.hasDeletePermission(user))
1155
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1156

    
1157
                file.setDeleted(true);
1158
                dao.update(file);
1159
                touchParentFolders(parent, user, new Date());
1160
        }
1161

    
1162
        @Override
1163
        public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1164
                if (userId == null)
1165
                        throw new ObjectNotFoundException("No user specified");
1166
                if (ownerId == null)
1167
                        throw new ObjectNotFoundException("No owner specified");
1168
                if (fileId == null)
1169
                        throw new ObjectNotFoundException("No file specified");
1170
                if (StringUtils.isEmpty(dest))
1171
                        throw new ObjectNotFoundException("No destination specified");
1172

    
1173
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1174
                if (!(destination instanceof FolderDTO))
1175
                        throw new ObjectNotFoundException("Destination parent folder not found");
1176
                FolderDTO parent = (FolderDTO) destination;
1177
                moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1178
        }
1179

    
1180
        @Override
1181
        public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1182
                if (userId == null)
1183
                        throw new ObjectNotFoundException("No user specified");
1184
                if (fileId == null)
1185
                        throw new ObjectNotFoundException("No file specified");
1186
                if (destId == null)
1187
                        throw new ObjectNotFoundException("No destination specified");
1188
                if (StringUtils.isEmpty(destName))
1189
                        throw new ObjectNotFoundException("No destination file name specified");
1190

    
1191
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1192
                Folder source = file.getFolder();
1193
                Folder destination = dao.getEntityById(Folder.class, destId);
1194

    
1195
                User owner = dao.getEntityById(User.class, userId);
1196
                if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1197
                        throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1198

    
1199
                // if the destination folder belongs to another user:
1200
                if (!file.getOwner().equals(destination.getOwner())) {
1201
                        // (a) check if the destination quota allows the move
1202
                        if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1203
                                throw new QuotaExceededException("Not enough free space available");
1204
                        User newOwner = destination.getOwner();
1205
                        // (b) if quota OK, change the owner of the file
1206
                        file.setOwner(newOwner);
1207
                        // if the file has no permission for the new owner, add it
1208
                        Permission ownerPermission = null;
1209
                        for (final Permission p : file.getPermissions())
1210
                                if (p.getUser() != null)
1211
                                        if (p.getUser().equals(newOwner)) {
1212
                                                ownerPermission = p;
1213
                                                break;
1214
                                        }
1215
                        if (ownerPermission == null) {
1216
                                ownerPermission = new Permission();
1217
                                ownerPermission.setUser(newOwner);
1218
                                file.addPermission(ownerPermission);
1219
                        }
1220
                        ownerPermission.setRead(true);
1221
                        ownerPermission.setWrite(true);
1222
                        ownerPermission.setModifyACL(true);
1223
                }
1224
                // move the file to the destination folder
1225
                file.setFolder(destination);
1226
                touchParentFolders(source, owner, new Date());
1227
                touchParentFolders(destination, owner, new Date());
1228
        }
1229

    
1230
        @Override
1231
        public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1232
                if (userId == null)
1233
                        throw new ObjectNotFoundException("No user specified");
1234
                if (ownerId == null)
1235
                        throw new ObjectNotFoundException("No owner specified");
1236
                if (folderId == null)
1237
                        throw new ObjectNotFoundException("No folder specified");
1238
                if (StringUtils.isEmpty(dest))
1239
                        throw new ObjectNotFoundException("No destination specified");
1240

    
1241
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1242
                if (!(destination instanceof FolderDTO))
1243
                        throw new ObjectNotFoundException("Destination parent folder not found");
1244
                FolderDTO parent = (FolderDTO) destination;
1245
                moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1246
        }
1247

    
1248
        @Override
1249
        public void moveFolder(Long userId, Long folderId, Long destId, String destName)
1250
                        throws ObjectNotFoundException, InsufficientPermissionsException,
1251
                        QuotaExceededException {
1252
                Folder source = dao.getEntityById(Folder.class, folderId);
1253
                Folder destination = dao.getEntityById(Folder.class, destId);
1254
                User user = dao.getEntityById(User.class, userId);
1255
                User sourceOwner = source.getOwner();
1256
                User destinationOwner = destination.getOwner();
1257
                // Do not move trashed folders and contents.
1258
                if (source.isDeleted())
1259
                        return;
1260
                // Check permissions.
1261
                if (!destination.hasWritePermission(user)
1262
                                || !source.hasReadPermission(user)
1263
                                || !source.hasWritePermission(user))
1264
                        throw new InsufficientPermissionsException("You don't have the " +
1265
                                        "necessary permissions");
1266
                // Use the same timestamp for all subsequent modifications to make
1267
                // changes appear simultaneous.
1268
                Date now = new Date();
1269
                // If source and destination are not in the same user's namespace,
1270
                // change owners and check quota.
1271
                if (!sourceOwner.equals(destinationOwner)) {
1272
                        changeOwner(source, destinationOwner, user, now);
1273
                        if (getQuotaLeft(destinationOwner.getId()) < 0)
1274
                                throw new QuotaExceededException("Not enough free space " +
1275
                                                "available in destination folder");
1276
                }
1277
                // Perform the move.
1278
                Folder oldParent = source.getParent();
1279
                oldParent.removeSubfolder(source);
1280
                destination.addSubfolder(source);
1281
                // Mark the former parent and destination trees upwards as modified.
1282
                touchParentFolders(oldParent, user, now);
1283
                touchParentFolders(source, user, now);
1284
        }
1285

    
1286
        /**
1287
         * Recursively change the owner of the specified folder and all of its
1288
         * contents to the specified owner. Also mark them all as modified with the
1289
         * specified modifier and modificationDate.
1290
         */
1291
        private void changeOwner(Folder folder, User owner, User modifier, Date modificationDate) {
1292
                for (FileHeader file: folder.getFiles()) {
1293
                        file.setOwner(owner);
1294
                        file.getAuditInfo().setModificationDate(modificationDate);
1295
                        file.getAuditInfo().setModifiedBy(modifier);
1296
                }
1297
                for (Folder sub: folder.getSubfolders())
1298
                        changeOwner(sub, owner, modifier, modificationDate);
1299
                folder.setOwner(owner);
1300
                folder.getAuditInfo().setModificationDate(modificationDate);
1301
                folder.getAuditInfo().setModifiedBy(modifier);
1302
        }
1303

    
1304
        @Override
1305
        public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1306
                // Validate.
1307
                if (userId == null)
1308
                        throw new ObjectNotFoundException("No user specified");
1309

    
1310
                // Do the actual work.
1311
                final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1312
                final List<FileHeader> files = dao.getDeletedFiles(userId);
1313
                for (final FileHeader f : files)
1314
                        result.add(f.getDTO());
1315
                return result;
1316
        }
1317

    
1318
        @Override
1319
        public void removeFileFromTrash(Long userId, Long fileId)
1320
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1321
                if (userId == null)
1322
                        throw new ObjectNotFoundException("No user specified");
1323
                if (fileId == null)
1324
                        throw new ObjectNotFoundException("No file specified");
1325

    
1326
                // Do the actual work.
1327
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1328
                Folder parent = file.getFolder();
1329
                if (parent == null)
1330
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1331
                User user = dao.getEntityById(User.class, userId);
1332
                if (!file.hasDeletePermission(user))
1333
                        throw new InsufficientPermissionsException("User " + user.getUsername() +
1334
                                                " cannot restore file " + file.getName());
1335

    
1336
                file.setDeleted(false);
1337
                dao.update(file);
1338
                touchParentFolders(parent, user, new Date());
1339
        }
1340

    
1341
        @Override
1342
        public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1343
                if (userId == null)
1344
                        throw new ObjectNotFoundException("No user specified");
1345
                if (folderId == null)
1346
                        throw new ObjectNotFoundException("No folder specified");
1347
                Folder folder = dao.getEntityById(Folder.class, folderId);
1348
                User user = dao.getEntityById(User.class, userId);
1349
                if (!folder.hasDeletePermission(user))
1350
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1351
                folder.setDeleted(true);
1352
                dao.update(folder);
1353
                touchParentFolders(folder, user, new Date());
1354
                for (FileHeader file : folder.getFiles())
1355
                        moveFileToTrash(userId, file.getId());
1356
                for (Folder subFolder : folder.getSubfolders())
1357
                        moveFolderToTrash(userId, subFolder.getId());
1358

    
1359
        }
1360

    
1361
        @Override
1362
        public void removeFolderFromTrash(Long userId, Long folderId)
1363
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1364
                if (userId == null)
1365
                        throw new ObjectNotFoundException("No user specified");
1366
                if (folderId == null)
1367
                        throw new ObjectNotFoundException("No folder specified");
1368
                Folder folder = dao.getEntityById(Folder.class, folderId);
1369
                User user = dao.getEntityById(User.class, userId);
1370
                if (!folder.hasDeletePermission(user))
1371
                        throw new InsufficientPermissionsException("User " + user.getUsername() +
1372
                                                " cannot restore folder " + folder.getName());
1373
                folder.setDeleted(false);
1374
                for (FileHeader file : folder.getFiles())
1375
                        removeFileFromTrash(userId, file.getId());
1376
                for (Folder subFolder : folder.getSubfolders())
1377
                        removeFolderFromTrash(userId, subFolder.getId());
1378
                dao.update(folder);
1379
                touchParentFolders(folder, user, new Date());
1380
        }
1381

    
1382
        @Override
1383
        public List<FolderDTO> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1384
                List<Folder> folders = dao.getDeletedRootFolders(userId);
1385
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1386
                for (Folder folder : folders)
1387
                        result.add(folder.getDTO());
1388
                return result;
1389
        }
1390

    
1391
        @Override
1392
        public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1393
                List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1394
                for (FolderDTO fdto : deletedRootFolders)
1395
                        deleteFolder(userId, fdto.getId());
1396
                List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1397
                for (FileHeaderDTO filedto : deletedFiles)
1398
                        deleteFile(userId, filedto.getId());
1399
        }
1400

    
1401
        @Override
1402
        public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1403
                List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1404
                for (FolderDTO fdto : deletedRootFolders)
1405
                        removeFolderFromTrash(userId, fdto.getId());
1406
                List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1407
                for (FileHeaderDTO filedto : deletedFiles)
1408
                        removeFileFromTrash(userId, filedto.getId());
1409
        }
1410

    
1411
        @Override
1412
        public User createUser(String username, String name, String mail,
1413
                                String idp, String idpid) throws ObjectNotFoundException {
1414
                if (username == null)
1415
                        throw new ObjectNotFoundException("No username specified");
1416
                if (name == null)
1417
                        throw new ObjectNotFoundException("No name specified");
1418

    
1419
                User user = new User();
1420
                user.setUsername(username);
1421
                user.setName(name);
1422
                user.setEmail(mail);
1423
                user.setIdentityProvider(idp);
1424
                user.setIdentityProviderId(idpid);
1425
                Date now = new Date();
1426
                AuditInfo auditInfo = new AuditInfo();
1427
                auditInfo.setCreationDate(now);
1428
                auditInfo.setModificationDate(now);
1429
                user.setAuditInfo(auditInfo);
1430
                user.generateAuthToken();
1431
                user.generateWebDAVPassword();
1432
                // Set the default user class to the one with the lowest quota.
1433
                user.setUserClass(getUserClasses().get(0));
1434
                dao.create(user);
1435
                // Make sure we get an ID in the user object.
1436
                dao.flush();
1437
                // Create the root folder for the user.
1438
                createFolder(user.getName(), null, user);
1439
                return user;
1440
        }
1441

    
1442
        @Override
1443
        public List<UserClass> getUserClasses() {
1444
                List<UserClass> classes = dao.getUserClasses();
1445
                // Create a default user class for first-time use. Afterwards, the
1446
                // admin should modify or add to the userclass table.
1447
                if (classes.size() == 0) {
1448
                        UserClass defaultClass = new UserClass();
1449
                        defaultClass.setName("default");
1450
                        Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L));
1451
                        defaultClass.setQuota(defaultQuota);
1452
                        dao.create(defaultClass);
1453
                        classes.add(defaultClass);
1454
                }
1455
                return classes;
1456
        }
1457

    
1458
        @Override
1459
        public User findUserByEmail(String email) {
1460
                return dao.findUserByEmail(email);
1461
        }
1462

    
1463
        @Override
1464
        public void updateUser(User user) {
1465
                dao.update(user);
1466
        }
1467

    
1468
        @Override
1469
        public User findUser(String username) {
1470
                if (username == null)
1471
                        return null;
1472
                return dao.findUser(username);
1473
        }
1474

    
1475
        @Override
1476
        public User updateUserToken(Long userId) throws ObjectNotFoundException {
1477
                if (userId == null)
1478
                        throw new ObjectNotFoundException("No user specified");
1479
                User user = dao.getEntityById(User.class, userId);
1480
                user.generateAuthToken();
1481
                return user;
1482
        }
1483

    
1484
        @Override
1485
        public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1486
                if (userId == null)
1487
                        throw new ObjectNotFoundException("No user specified");
1488
                if (folderId == null)
1489
                        throw new ObjectNotFoundException("No folder specified");
1490
                User user = dao.getEntityById(User.class, userId);
1491
                Folder folder = dao.getEntityById(Folder.class, folderId);
1492
                if(!folder.hasReadPermission(user))
1493
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1494
                Set<Permission> perms = folder.getPermissions();
1495
                Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1496
                for (Permission perm : perms)
1497
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1498
                                result.add(perm.getDTO());
1499
                for (Permission perm : perms)
1500
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1501
                        } else
1502
                                result.add(perm.getDTO());
1503
                return result;
1504

    
1505
        }
1506

    
1507
        /**
1508
         * Set the provided permissions as the new permissions of the specified
1509
         * folder.
1510
         *
1511
         * @param user
1512
         * @param folder
1513
         * @param permissions
1514
         * @throws ObjectNotFoundException
1515
         * @throws InsufficientPermissionsException
1516
         */
1517
        private void setFolderPermissions(User user, Folder folder, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1518
                if (permissions != null && !permissions.isEmpty()) {
1519
                        User owner = folder.getOwner();
1520
                        PermissionDTO ownerPerm = null;
1521
                        for (PermissionDTO dto : permissions)
1522
                                if (dto.getUser() != null && dto.getUser().getId().equals(owner.getId())) {
1523
                                        ownerPerm = dto;
1524
                                        break;
1525
                                }
1526
                        if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1527
                                throw new InsufficientPermissionsException("Can't remove permissions from owner");
1528
                        // Delete previous entries
1529
                        for (Permission perm: folder.getPermissions())
1530
                                dao.delete(perm);
1531
                        folder.getPermissions().clear();
1532
                        for (PermissionDTO dto : permissions) {
1533
                                // Skip 'empty' permission entries.
1534
                                if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1535
                                folder.addPermission(getPermission(dto));
1536
                        }
1537
                        dao.update(folder);
1538
                        for (FileHeader file : folder.getFiles()) {
1539
                                setFilePermissions(file, permissions);
1540
                                Date now = new Date();
1541
                                file.getAuditInfo().setModificationDate(now);
1542
                                file.getAuditInfo().setModifiedBy(user);
1543
                        }
1544
                        for (Folder sub : folder.getSubfolders())
1545
                                setFolderPermissions(user, sub, permissions);
1546
                }
1547
        }
1548

    
1549
        private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1550
                Permission res = new Permission();
1551
                if (dto.getGroup() != null)
1552
                        res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1553
                else if (dto.getUser() != null)
1554
                        if (dto.getUser().getId() == null)
1555
                                res.setUser(dao.getUser(dto.getUser().getUsername()));
1556
                        else
1557
                                res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1558
                res.setRead(dto.hasRead());
1559
                res.setWrite(dto.hasWrite());
1560
                res.setModifyACL(dto.hasModifyACL());
1561
                return res;
1562
        }
1563

    
1564
        /* (non-Javadoc)
1565
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1566
         */
1567
        @Override
1568
        public List<UserDTO> getUsersByUserNameLike(String username) {
1569
                List<User> users = dao.getUsersByUserNameLike(username);
1570
                List<UserDTO> result = new ArrayList<UserDTO>();
1571
                for (User u : users)
1572
                        result.add(u.getDTO());
1573
                return result;
1574

    
1575
        }
1576

    
1577
        /* (non-Javadoc)
1578
         * @see gr.ebs.gss.server.ejb.ExternalAPI#addUserToGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1579
         */
1580
        @Override
1581
        public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1582
                if (userId == null)
1583
                        throw new ObjectNotFoundException("No user specified");
1584
                if (groupId == null)
1585
                        throw new ObjectNotFoundException("No group specified");
1586
                if (userToAddId == null)
1587
                        throw new ObjectNotFoundException("No user to add specified");
1588
                User user = dao.getEntityById(User.class, userId);
1589
                Group group = dao.getEntityById(Group.class, groupId);
1590
                if (!group.getOwner().equals(user))
1591
                        throw new InsufficientPermissionsException();
1592
                User userToAdd = dao.getEntityById(User.class, userToAddId);
1593
                if (group.contains(userToAdd))
1594
                        throw new DuplicateNameException("User already exists in group");
1595
                group.getMembers().add(userToAdd);
1596
                dao.update(group);
1597

    
1598
        }
1599

    
1600
        @Override
1601
        public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1602
                if (userId == null)
1603
                        throw new ObjectNotFoundException("No user specified");
1604
                User user = dao.getEntityById(User.class, userId);
1605
                user.invalidateAuthToken();
1606
                return;
1607
        }
1608

    
1609
        @Override
1610
        public List<FolderDTO> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1611
                if (userId == null)
1612
                        throw new ObjectNotFoundException("No user specified");
1613
                List<Folder> folders = dao.getSharedRootFolders(userId);
1614
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1615
                for (Folder f : folders) {
1616
                        FolderDTO dto = f.getDTO();
1617
                        dto.setSubfolders(getSharedSubfolders(userId, f.getId()));
1618
                        result.add(dto);
1619
                }
1620
                return result;
1621
        }
1622

    
1623
        /* (non-Javadoc)
1624
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeMemberFromGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1625
         */
1626
        @Override
1627
        public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1628
                if (userId == null)
1629
                        throw new ObjectNotFoundException("No user specified");
1630
                if (groupId == null)
1631
                        throw new ObjectNotFoundException("No group specified");
1632
                if (memberId == null)
1633
                        throw new ObjectNotFoundException("No member specified");
1634
                User owner = dao.getEntityById(User.class, userId);
1635
                Group group = dao.getEntityById(Group.class, groupId);
1636
                User member = dao.getEntityById(User.class, memberId);
1637
                if (!group.getOwner().equals(owner))
1638
                        throw new InsufficientPermissionsException("User is not the owner of the group");
1639
                group.removeMemberFromGroup(member);
1640
                dao.update(group);
1641

    
1642
        }
1643

    
1644
        @Override
1645
        public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1646
                List<User> users = dao.getUsersSharingFoldersForUser(userId);
1647
                List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1648
                List<UserDTO> res = new ArrayList<UserDTO>();
1649
                for (User u : users)
1650
                        res.add(u.getDTO());
1651
                for(User fu : usersFiles)
1652
                        if(!users.contains(fu))
1653
                                res.add(fu.getDTO());
1654
                return res;
1655
        }
1656

    
1657
        @Override
1658
        public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1659
                if (userId == null)
1660
                        throw new ObjectNotFoundException("No user specified");
1661
                if (fileId == null)
1662
                        throw new ObjectNotFoundException("No folder specified");
1663
                User user = dao.getEntityById(User.class, userId);
1664
                FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1665
                if(!folder.hasReadPermission(user))
1666
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1667
                Set<Permission> perms = folder.getPermissions();
1668
                Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1669
                for (Permission perm : perms)
1670
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1671
                                result.add(perm.getDTO());
1672
                for (Permission perm : perms)
1673
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1674
                        } else
1675
                                result.add(perm.getDTO());
1676
                return result;
1677
        }
1678

    
1679
        /**
1680
         * Set the provided permissions as the new permissions of the specified
1681
         * file. This method sets the modification date/user attributes to the
1682
         * current values as a side effect.
1683
         *
1684
         * @param file
1685
         * @param permissions
1686
         * @throws ObjectNotFoundException
1687
         * @throws InsufficientPermissionsException
1688
         */
1689
        private void setFilePermissions(FileHeader file,
1690
                                Set<PermissionDTO> permissions)
1691
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1692
                if (permissions != null && !permissions.isEmpty()) {
1693
                        PermissionDTO ownerPerm = null;
1694
                        for (PermissionDTO dto : permissions)
1695
                                if (dto.getUser() != null && dto.getUser().getId().equals(file.getOwner().getId())) {
1696
                                        ownerPerm = dto;
1697
                                        break;
1698
                                }
1699
                        if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1700
                                throw new InsufficientPermissionsException("Can't remove permissions from owner");
1701
                        // Delete previous entries.
1702
                        for (Permission perm: file.getPermissions())
1703
                                dao.delete(perm);
1704
                        file.getPermissions().clear();
1705
                        for (PermissionDTO dto : permissions) {
1706
                                // Skip 'empty' permission entries.
1707
                                if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1708
                                file.addPermission(getPermission(dto));
1709
                        }
1710
                        dao.flush();
1711
                }
1712
        }
1713

    
1714
        @Override
1715
        public List<FileHeaderDTO> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1716
                if (userId == null)
1717
                        throw new ObjectNotFoundException("No user specified");
1718
                List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1719
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1720
                for (FileHeader f : files)
1721
                        result.add(f.getDTO());
1722
                return result;
1723
        }
1724

    
1725
        @Override
1726
        public List<FileHeaderDTO> getSharedFiles(Long userId) throws ObjectNotFoundException {
1727
                if (userId == null)
1728
                        throw new ObjectNotFoundException("No user specified");
1729
                List<FileHeader> files = dao.getSharedFiles(userId);
1730
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1731
                for (FileHeader f : files)
1732
                        result.add(f.getDTO());
1733
                return result;
1734
        }
1735

    
1736
        @Override
1737
        public List<FolderDTO> getSharedFolders(Long userId) throws ObjectNotFoundException {
1738
                if (userId == null)
1739
                        throw new ObjectNotFoundException("No user specified");
1740
                List<Folder> folders = dao.getSharedFolders(userId);
1741
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1742
                for (Folder f : folders)
1743
                        result.add(f.getDTO());
1744
                return result;
1745
        }
1746

    
1747
        /* (non-Javadoc)
1748
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getSharedFiles(java.lang.Long, java.lang.Long)
1749
         */
1750
        @Override
1751
        public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1752
                if (ownerId == null)
1753
                        throw new ObjectNotFoundException("No owner specified");
1754
                if (callingUserId == null)
1755
                        throw new ObjectNotFoundException("No calling user specified");
1756
                List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1757
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1758
                for (FileHeader f : folders)
1759
                        result.add(f.getDTO());
1760
                return result;
1761
        }
1762

    
1763
        @Override
1764
        public List<FolderDTO> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1765
                if (ownerId == null)
1766
                        throw new ObjectNotFoundException("No owner specified");
1767
                if (callingUserId == null)
1768
                        throw new ObjectNotFoundException("No calling user specified");
1769
                List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1770
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1771
                for (Folder f : folders) {
1772
                        FolderDTO dto = f.getDTO();
1773
                        dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1774
                        result.add(dto);
1775
                }
1776
                return result;
1777

    
1778
        }
1779

    
1780
        @Override
1781
        public List<FolderDTO> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1782
                if (userId == null)
1783
                        throw new ObjectNotFoundException("No user specified");
1784
                if (folderId == null)
1785
                        throw new ObjectNotFoundException("No folder specified");
1786
                User user = dao.getEntityById(User.class, userId);
1787
                Folder folder = dao.getEntityById(Folder.class, folderId);
1788
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1789
                if (folder.isShared(user))
1790
                        for (Folder f : folder.getSubfolders())
1791
                                if (f.isShared(user) && !f.isDeleted())
1792
                                        result.add(f.getDTO());
1793
                return result;
1794
        }
1795

    
1796
        @Override
1797
        public List<FolderDTO> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1798
                if (userId == null)
1799
                        throw new ObjectNotFoundException("No user specified");
1800
                if (callingUserId == null)
1801
                        throw new ObjectNotFoundException("No user specified");
1802
                if (folderId == null)
1803
                        throw new ObjectNotFoundException("No folder specified");
1804
                User user = dao.getEntityById(User.class, callingUserId);
1805
                Folder folder = dao.getEntityById(Folder.class, folderId);
1806
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1807
                if (folder.isSharedForOtherUser(user))
1808
                        for (Folder f : folder.getSubfolders())
1809
                                if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1810
                                        FolderDTO dto = f.getDTO();
1811
                                        dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId()));
1812
                                        result.add(dto);
1813
                                }
1814
                return result;
1815

    
1816
        }
1817

    
1818
        /* (non-Javadoc)
1819
         * @see gr.ebs.gss.server.ejb.ExternalAPI#searchFiles(java.lang.Long, java.lang.String)
1820
         */
1821
        @Override
1822
        public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1823
                if (userId == null)
1824
                        throw new ObjectNotFoundException("No user specified");
1825
                User user = getUser(userId);
1826
                if (query == null)
1827
                        throw new ObjectNotFoundException("No query specified");
1828
                List<FileHeader> files = search(user.getId(), query);
1829
                List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1830
                for(FileHeader f : files)
1831
                        res.add(f.getDTO());
1832
                return res;
1833
        }
1834

    
1835
        /**
1836
         * Performs the actuals search on the solr server and returns the results
1837
         *
1838
         * We have to use the dismax query type (instead of the
1839
         * standard) because it allows for search time field boosting. This is because we can't use indexing
1840
         * time field boosting due to the patched rich indexing API that does not allow it
1841
         *
1842
         * @param userId
1843
         * @param query
1844
         * @return a List of FileHeader objects
1845
         */
1846
        private List<FileHeader> search(Long userId, String query) {
1847
                try {
1848
                        HttpClient httpClient = new HttpClient();
1849

    
1850
                        GetMethod method = new GetMethod(getConfiguration().getString("solrSelectUrl"));
1851
                        NameValuePair[] params = {new NameValuePair("qt", "dismax"),
1852
                                                                                new NameValuePair("q", query),
1853
                                                                                new NameValuePair("sort", "score desc"),
1854
                                                                                new NameValuePair("indent", "on")};
1855
                        method.setQueryString(params);
1856
                        int retryCount = 0;
1857
                        int statusCode = 0;
1858
                        String response = null;
1859
                        do {
1860
                                statusCode = httpClient.executeMethod(method);
1861
                                logger.debug("HTTP status: " + statusCode);
1862
                                response = method.getResponseBodyAsString();
1863
                                logger.debug(response);
1864
                                retryCount++;
1865
                                if (statusCode != 200 && retryCount < 3)
1866
                                        try {
1867
                                                Thread.sleep(3000); //Give Solr a little time to be available
1868
                                        } catch (InterruptedException e) {
1869
                                        }
1870
                        } while (statusCode != 200 && retryCount < 3);
1871
                        if (statusCode != 200)
1872
                                throw new EJBException("Search query return error:\n" + response);
1873

    
1874
                        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1875
                        DocumentBuilder db = dbf.newDocumentBuilder();
1876
                        Document doc = db.parse(method.getResponseBodyAsStream());
1877
                        method.releaseConnection();
1878

    
1879
                        Node root = doc.getElementsByTagName("response").item(0);
1880
                        Node lst = root.getFirstChild().getNextSibling();
1881
                        Node status = lst.getFirstChild().getNextSibling();
1882
                        if (status.getAttributes().getNamedItem("name").getNodeValue().equals("status") &&
1883
                                status.getTextContent().equals("0")) {
1884
                                List<FileHeader> fileResult = new ArrayList<FileHeader>();
1885
                                Node result = lst.getNextSibling().getNextSibling();
1886
                                NodeList docs = result.getChildNodes();
1887
                                User user = getUser(userId);
1888
                                for (int i=1; i<docs.getLength(); i=i+2) {
1889
                                        Node d = docs.item(i);
1890
                                        NodeList docData = d.getChildNodes();
1891
                                        for (int j=1; j<docData.getLength(); j=j+2) {
1892
                                                Node dd = docData.item(j);
1893
                                                if (dd.getAttributes().item(0).getNodeName().equals("name") &&
1894
                                                        dd.getAttributes().item(0).getNodeValue().equals("id")) {
1895
                                                        Long fileId = Long.valueOf(dd.getTextContent());
1896
                                                        try {
1897
                                                                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1898
                                                                if (file.hasReadPermission(user)) {
1899
                                                                        fileResult.add(file);
1900
                                                                        logger.debug("File added " + fileId);
1901
                                                                }
1902
                                                        } catch (ObjectNotFoundException e) {
1903
                                                                logger.warn("Search result not found", e);
1904
                                                        }
1905
                                                }
1906
                                        }
1907
                                }
1908
                                return fileResult;
1909
                        }
1910
                        throw new EJBException();
1911
                } catch (HttpException e) {
1912
                        throw new EJBException(e);
1913
                } catch (IOException e) {
1914
                        throw new EJBException(e);
1915
                } catch (SAXException e) {
1916
                        throw new EJBException(e);
1917
                } catch (ParserConfigurationException e) {
1918
                        throw new EJBException(e);
1919
                } catch (ObjectNotFoundException e) {
1920
                        throw new EJBException(e);
1921
                }
1922
        }
1923

    
1924
        /* (non-Javadoc)
1925
         * @see gr.ebs.gss.server.ejb.ExternalAPI#copyFiles(java.lang.Long, java.util.List, java.lang.Long)
1926
         */
1927
        @Override
1928
        public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1929
                for(Long l : fileIds){
1930
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1931
                        copyFile(userId, l, destId, file.getName());
1932
                }
1933

    
1934

    
1935
        }
1936

    
1937
        /* (non-Javadoc)
1938
         * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFiles(java.lang.Long, java.util.List, java.lang.Long)
1939
         */
1940
        @Override
1941
        public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1942
                for(Long l : fileIds){
1943
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1944
                        moveFile(userId, l, destId, file.getName());
1945
                }
1946

    
1947
        }
1948

    
1949
        /* (non-Javadoc)
1950
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFiles(java.lang.Long, java.util.List)
1951
         */
1952
        @Override
1953
        public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1954
                if (userId == null)
1955
                        throw new ObjectNotFoundException("No user specified");
1956
                final User user = dao.getEntityById(User.class, userId);
1957
                List<String> filesToRemove = new ArrayList<String>();
1958
                //first delete database objects
1959
                for(Long fileId : fileIds){
1960
                        if (fileId == null)
1961
                                throw new ObjectNotFoundException("No file specified");
1962
                        final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1963
                        final Folder parent = file.getFolder();
1964
                        if (parent == null)
1965
                                throw new ObjectNotFoundException("The specified file has no parent folder");
1966
                        if (!file.hasDeletePermission(user))
1967
                                throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1968

    
1969
                        parent.removeFile(file);
1970
                        for (final FileBody body : file.getBodies())
1971
                                filesToRemove.add(body.getStoredFilePath());
1972
                        dao.delete(file);
1973
                        touchParentFolders(parent, user, new Date());
1974
                }
1975
                //then remove physical files if everything is ok
1976
                for(String physicalFileName : filesToRemove)
1977
                        deleteActualFile(physicalFileName);
1978
                //then unindex deleted files
1979
                for(Long fileId : fileIds)
1980
                        indexFile(fileId, true);
1981

    
1982
        }
1983

    
1984
        /* (non-Javadoc)
1985
         * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFilesToTrash(java.lang.Long, java.util.List)
1986
         */
1987
        @Override
1988
        public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1989
                for(Long l : fileIds)
1990
                        moveFileToTrash(userId, l);
1991

    
1992
        }
1993

    
1994
        @Override
1995
        public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1996
                for(Long l : fileIds)
1997
                        removeFileFromTrash(userId, l);
1998

    
1999
        }
2000

    
2001
        @Override
2002
        public Nonce createNonce(Long userId) throws ObjectNotFoundException {
2003
                if (userId == null)
2004
                        throw new ObjectNotFoundException("No user specified");
2005
                User user = dao.getEntityById(User.class, userId);
2006
                Nonce nonce = Nonce.createNonce(user.getId());
2007
                dao.create(nonce);
2008
                return nonce;
2009
        }
2010

    
2011
        @Override
2012
        public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
2013
                if (userId == null)
2014
                        throw new ObjectNotFoundException("No user specified");
2015
                if (nonce == null)
2016
                        throw new ObjectNotFoundException("No nonce specified");
2017
                return dao.getNonce(nonce, userId);
2018
        }
2019

    
2020
        @Override
2021
        public void removeNonce(Long id) throws ObjectNotFoundException {
2022
                if (id == null)
2023
                        throw new ObjectNotFoundException("No nonce specified");
2024
                Nonce nonce = dao.getEntityById(Nonce.class, id);
2025
                dao.delete(nonce);
2026
        }
2027

    
2028
        @Override
2029
        public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
2030
                if (userId == null)
2031
                        throw new ObjectNotFoundException("No user specified");
2032
                User user = dao.getEntityById(User.class, userId);
2033
                user.setNonce(nonce);
2034
                user.setNonceExpiryDate(nonceExpiryDate);
2035
        }
2036

    
2037
        /* (non-Javadoc)
2038
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserStatistics(java.lang.Long)
2039
         */
2040
        @Override
2041
        public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
2042
                if (userId == null)
2043
                        throw new ObjectNotFoundException("No user specified");
2044
                StatsDTO stats = new StatsDTO();
2045
                stats.setFileCount(dao.getFileCount(userId));
2046
                Long fileSize = dao.getFileSize(userId);
2047
                stats.setFileSize(fileSize);
2048
                Long quota = getQuota(userId);
2049
                Long quotaLeft = quota - fileSize;
2050
                stats.setQuotaLeftSize(quotaLeft);
2051
                return stats;
2052
        }
2053

    
2054
        /* (non-Javadoc)
2055
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getVersions(java.lang.Long, java.lang.Long)
2056
         */
2057
        @Override
2058
        public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2059
                if (userId == null)
2060
                        throw new ObjectNotFoundException("No user specified");
2061
                if (fileId == null)
2062
                        throw new ObjectNotFoundException("No file specified");
2063
                User user = dao.getEntityById(User.class, userId);
2064
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2065
                if(!header.hasReadPermission(user))
2066
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2067
                List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
2068
                for(int i = header.getBodies().size()-1 ; i>=0; i--)
2069
                        result.add(header.getBodies().get(i).getDTO());
2070
                return result;
2071
        }
2072

    
2073
        /* (non-Javadoc)
2074
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeVersion(java.lang.Long, java.lang.Long, java.lang.Long)
2075
         */
2076
        @Override
2077
        public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
2078
                if (userId == null)
2079
                        throw new ObjectNotFoundException("No user specified");
2080
                if (fileId == null)
2081
                        throw new ObjectNotFoundException("No file specified");
2082
                if (bodyId == null)
2083
                        throw new ObjectNotFoundException("No body specified");
2084
                User user = dao.getEntityById(User.class, userId);
2085
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2086
                if(!header.hasWritePermission(user))
2087
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2088
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
2089
                if(body.equals(header.getCurrentBody())){
2090

    
2091
                        if(header.getBodies().size() == 1)
2092
                                throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
2093
                        for(FileBody b : header.getBodies())
2094
                                if(b.getVersion() == body.getVersion()-1)
2095
                                        header.setCurrentBody(b);
2096
                }
2097
                deleteActualFile(body.getStoredFilePath());
2098
                header.getBodies().remove(body);
2099

    
2100
                Folder parent = header.getFolder();
2101
                touchParentFolders(parent, user, new Date());
2102

    
2103
        }
2104

    
2105
        @Override
2106
        public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException,  GSSIOException, QuotaExceededException {
2107
                if (userId == null)
2108
                        throw new ObjectNotFoundException("No user specified");
2109
                if (fileId == null)
2110
                        throw new ObjectNotFoundException("No file specified");
2111
                User user = dao.getEntityById(User.class, userId);
2112
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2113
                if(!header.hasWritePermission(user))
2114
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2115
                FileBody body = dao.getFileVersion(fileId, version);
2116
                final File fileContents = new File(body.getStoredFilePath());
2117

    
2118
                try {
2119
                        updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
2120
                } catch (FileNotFoundException e) {
2121
                        throw new GSSIOException(e);
2122
                }
2123

    
2124
        }
2125

    
2126
        /* (non-Javadoc)
2127
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2128
         */
2129
        @Override
2130
        public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2131
                if (userId == null)
2132
                        throw new ObjectNotFoundException("No user specified");
2133
                if (fileId == null)
2134
                        throw new ObjectNotFoundException("No file specified");
2135
                User user = dao.getEntityById(User.class, userId);
2136
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2137
                if(!header.hasWritePermission(user))
2138
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2139
                Iterator<FileBody> it = header.getBodies().iterator();
2140
                while(it.hasNext()){
2141
                        FileBody body = it.next();
2142
                        if(!body.equals(header.getCurrentBody())){
2143
                                deleteActualFile(body.getStoredFilePath());
2144
                                it.remove();
2145
                                dao.delete(body);
2146
                        }
2147
                }
2148
                header.getCurrentBody().setVersion(1);
2149

    
2150
                Folder parent = header.getFolder();
2151
                touchParentFolders(parent, user, new Date());
2152
        }
2153

    
2154
        /**
2155
         * Gets the quota left for specified user ID.
2156
         */
2157
        private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
2158
                Long fileSize = dao.getFileSize(userId);
2159
                Long quota = getQuota(userId);
2160
                return quota - fileSize;
2161
        }
2162

    
2163
        /**
2164
         * Gets the quota for specified user ID.
2165
         */
2166
        private Long getQuota(Long userId) throws ObjectNotFoundException{
2167
                return getUser(userId).getUserClass().getQuota();
2168
        }
2169

    
2170
        public void rebuildSolrIndex() {
2171
                MessageProducer sender = null;
2172
                Session session = null;
2173
                Connection qConn = null;
2174
                try {
2175
                        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2176
                        DocumentBuilder db = dbf.newDocumentBuilder();
2177
                        Document doc = db.newDocument();
2178
                        Node root = doc.createElement("delete");
2179
                        doc.appendChild(root);
2180
                        Node queryNode = doc.createElement("query");
2181
                        root.appendChild(queryNode);
2182
                        queryNode.appendChild(doc.createTextNode("*:*"));
2183

    
2184
                        TransformerFactory fact = TransformerFactory.newInstance();
2185
                        Transformer trans = fact.newTransformer();
2186
                        trans.setOutputProperty(OutputKeys.INDENT, "yes");
2187
                        StringWriter sw = new StringWriter();
2188
                        StreamResult sr = new StreamResult(sw);
2189
                        DOMSource source = new DOMSource(doc);
2190
                        trans.transform(source, sr);
2191
                        logger.debug(sw.toString());
2192

    
2193
                        HttpClient httpClient = new HttpClient();
2194
                        PostMethod method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2195
                        method.setRequestEntity(new StringRequestEntity(sw.toString()));
2196
                        int retryCount = 0;
2197
                        int statusCode = 0;
2198
                        String response = null;
2199
                        do {
2200
                                statusCode = httpClient.executeMethod(method);
2201
                                logger.debug("HTTP status: " + statusCode);
2202
                                response = method.getResponseBodyAsString();
2203
                                logger.debug(response);
2204
                                retryCount++;
2205
                                if (statusCode != 200 && retryCount < 3)
2206
                                        try {
2207
                                                Thread.sleep(10000); //Give Solr a little time to be available
2208
                                        } catch (InterruptedException e) {
2209
                                        }
2210
                        } while (statusCode != 200 && retryCount < 3);
2211
                        method.releaseConnection();
2212
                        if (statusCode != 200)
2213
                                throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response);
2214
                        List<Long> fileIds = dao.getAllFileIds();
2215

    
2216
                        Context jndiCtx = new InitialContext();
2217
                        ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
2218
                        Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
2219
                        qConn = factory.createConnection();
2220
                        session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
2221
                        sender = session.createProducer(queue);
2222

    
2223
                        for (Long id : fileIds) {
2224
                                MapMessage map = session.createMapMessage();
2225
                                map.setObject("id", id);
2226
                                map.setBoolean("delete", false);
2227
                                sender.send(map);
2228
                        }
2229
                        sendOptimize(httpClient, 0);
2230
                } catch (DOMException e) {
2231
                        throw new EJBException(e);
2232
                } catch (TransformerConfigurationException e) {
2233
                        throw new EJBException(e);
2234
                } catch (IllegalArgumentException e) {
2235
                        throw new EJBException(e);
2236
                } catch (HttpException e) {
2237
                        throw new EJBException(e);
2238
                } catch (UnsupportedEncodingException e) {
2239
                        throw new EJBException(e);
2240
                } catch (ParserConfigurationException e) {
2241
                        throw new EJBException(e);
2242
                } catch (TransformerException e) {
2243
                        throw new EJBException(e);
2244
                } catch (IOException e) {
2245
                        throw new EJBException(e);
2246
                } catch (NamingException e) {
2247
                        throw new EJBException(e);
2248
                } catch (JMSException e) {
2249
                        throw new EJBException(e);
2250
                }
2251
                finally {
2252
                        try {
2253
                                if (sender != null)
2254
                                        sender.close();
2255
                                if (session != null)
2256
                                        session.close();
2257
                                if (qConn != null)
2258
                                        qConn.close();
2259
                        }
2260
                        catch (JMSException e) {
2261
                                logger.warn(e);
2262
                        }
2263
                }
2264
        }
2265

    
2266
        /**
2267
         * Sends a optimize message to the solr server
2268
         *
2269
         * @param httpClient
2270
         * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive
2271
         *                                         calls to stop the recursion
2272
         * @throws UnsupportedEncodingException
2273
         * @throws IOException
2274
         * @throws HttpException
2275
         */
2276
        private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException {
2277
                PostMethod method = null;
2278
                try {
2279
                        logger.debug("Optimize retry: " + retryCount);
2280
                        method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2281
                        method.setRequestEntity(new StringRequestEntity("<optimize/>", "text/xml", "iso8859-1"));
2282
                        int statusCode = httpClient.executeMethod(method);
2283
                        logger.debug("HTTP status: " + statusCode);
2284
                        String response = method.getResponseBodyAsString();
2285
                        logger.debug(response);
2286
                        if (statusCode != 200 && retryCount < 2) {
2287
                                try {
2288
                                        Thread.sleep(10000); //Give Solr a little time to be available
2289
                                } catch (InterruptedException e) {
2290
                                }
2291
                                sendOptimize(httpClient, retryCount + 1);
2292
                        }
2293
                }
2294
                finally {
2295
                        if (method != null)
2296
                                method.releaseConnection();
2297
                }
2298
        }
2299

    
2300
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2301
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2302
                        InsufficientPermissionsException, QuotaExceededException {
2303
                // Validate.
2304
                if (userId == null)
2305
                        throw new ObjectNotFoundException("No user specified");
2306
                if (folderId == null)
2307
                        throw new ObjectNotFoundException("No folder specified");
2308
                String contentType = mimeType;
2309
                if (StringUtils.isEmpty(mimeType))
2310
                        contentType = DEFAULT_MIME_TYPE;
2311
                if (StringUtils.isEmpty(name))
2312
                        throw new ObjectNotFoundException("No file name specified");
2313
                if (dao.existsFolderOrFile(folderId, name))
2314
                        throw new DuplicateNameException("A folder or file with the name '" + name +
2315
                                                "' already exists at this level");
2316

    
2317
                // Do the actual work.
2318
                Folder parent = null;
2319
                try {
2320
                        parent = dao.getEntityById(Folder.class, folderId);
2321
                } catch (final ObjectNotFoundException onfe) {
2322
                        // Supply a more accurate problem description.
2323
                        throw new ObjectNotFoundException("Parent folder not found");
2324
                }
2325
                final User owner = dao.getEntityById(User.class, userId);
2326
                if (!parent.hasWritePermission(owner))
2327
                        throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2328
                final FileHeader file = new FileHeader();
2329
                file.setName(name);
2330
                parent.addFile(file);
2331
                // set file owner to folder owner
2332
                file.setOwner(parent.getOwner());
2333

    
2334
                final Date now = new Date();
2335
                final AuditInfo auditInfo = new AuditInfo();
2336
                auditInfo.setCreatedBy(owner);
2337
                auditInfo.setCreationDate(now);
2338
                auditInfo.setModifiedBy(owner);
2339
                auditInfo.setModificationDate(now);
2340
                file.setAuditInfo(auditInfo);
2341
                // TODO set the proper versioning flag on creation
2342
                file.setVersioned(false);
2343

    
2344
                for (final Permission p : parent.getPermissions()) {
2345
                        final Permission permission = new Permission();
2346
                        permission.setGroup(p.getGroup());
2347
                        permission.setUser(p.getUser());
2348
                        permission.setRead(p.getRead());
2349
                        permission.setWrite(p.getWrite());
2350
                        permission.setModifyACL(p.getModifyACL());
2351
                        file.addPermission(permission);
2352
                }
2353

    
2354
                // Create the file body.
2355
                try {
2356
                        createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2357
                } catch (FileNotFoundException e) {
2358
                        throw new GSSIOException(e);
2359
                }
2360
                touchParentFolders(parent, owner, new Date());
2361
                dao.flush();
2362
                indexFile(file.getId(), false);
2363

    
2364
                return file.getDTO();
2365
        }
2366

    
2367
        /* (non-Javadoc)
2368
         * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFileContents(java.lang.Long, java.lang.Long, java.lang.String, java.io.InputStream)
2369
         */
2370
        public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2371
                if (userId == null)
2372
                        throw new ObjectNotFoundException("No user specified");
2373
                if (fileId == null)
2374
                        throw new ObjectNotFoundException("No file specified");
2375
                String contentType = mimeType;
2376

    
2377
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2378

    
2379
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2380
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2381
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2382
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2383
                        contentType = identifyMimeType(file.getName());
2384

    
2385
                final User owner = dao.getEntityById(User.class, userId);
2386
                if (!file.hasWritePermission(owner))
2387
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2388
                final Date now = new Date();
2389
                final AuditInfo auditInfo = new AuditInfo();
2390
                auditInfo.setCreatedBy(owner);
2391
                auditInfo.setCreationDate(now);
2392
                auditInfo.setModifiedBy(owner);
2393
                auditInfo.setModificationDate(now);
2394
                try {
2395
                        createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2396
                } catch (FileNotFoundException e) {
2397
                        throw new GSSIOException(e);
2398
                }
2399
                Folder parent = file.getFolder();
2400
                touchParentFolders(parent, owner, new Date());
2401

    
2402
                indexFile(fileId, false);
2403
                return file.getDTO();
2404
        }
2405

    
2406
        /**
2407
         * Helper method for identifying mime type by examining the filename extension
2408
         *
2409
         * @param filename
2410
         * @return the mime type
2411
         */
2412
        private String identifyMimeType(String filename) {
2413
                if (filename.indexOf('.') != -1) {
2414
                        String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2415
                        if (".doc".equals(extension))
2416
                                return "application/msword";
2417
                        else if (".xls".equals(extension))
2418
                                return "application/vnd.ms-excel";
2419
                        else if (".ppt".equals(extension))
2420
                                return "application/vnd.ms-powerpoint";
2421
                        else if (".pdf".equals(extension))
2422
                                return "application/pdf";
2423
                        else if (".gif".equals(extension))
2424
                                return "image/gif";
2425
                        else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2426
                                return "image/jpeg";
2427
                        else if (".tiff".equals(extension) || ".tif".equals(extension))
2428
                                return "image/tiff";
2429
                        else if (".png".equals(extension))
2430
                                return "image/png";
2431
                        else if (".bmp".equals(extension))
2432
                                return "image/bmp";
2433
                }
2434
                // when all else fails assign the default mime type
2435
                return DEFAULT_MIME_TYPE;
2436
        }
2437

    
2438
        /**
2439
         * Helper method to create a new file body and attach it as the current body
2440
         * of the provided file header.
2441
         *
2442
         * @param name the original file name
2443
         * @param mimeType the content type
2444
         * @param fileSize the uploaded file size
2445
         * @param filePath the uploaded file full path
2446
         * @param header the file header that will be associated with the new body
2447
         * @param auditInfo the audit info
2448
         * @param owner the owner of the file
2449
         * @throws FileNotFoundException
2450
         * @throws QuotaExceededException
2451
         * @throws ObjectNotFoundException if the owner was not found
2452
         */
2453
        private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2454
                                FileHeader header, AuditInfo auditInfo)
2455
                        throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2456

    
2457
                long currentTotalSize = 0;
2458
                if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2459
                        currentTotalSize = header.getTotalSize();
2460
                Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2461
                if(quotaLeft < fileSize-currentTotalSize) {
2462
                        // quota exceeded -> delete the file
2463
                        deleteActualFile(filePath);
2464
                        throw new QuotaExceededException("Not enough free space available");
2465
                }
2466

    
2467
                FileBody body = new FileBody();
2468

    
2469
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2470
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2471
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2472
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2473
                        body.setMimeType(identifyMimeType(name));
2474
                else
2475
                        body.setMimeType(mimeType);
2476
                body.setAuditInfo(auditInfo);
2477
                body.setFileSize(fileSize);
2478
                body.setOriginalFilename(name);
2479
                body.setStoredFilePath(filePath);
2480
                //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2481
                if(!header.isVersioned() && header.getCurrentBody() != null){
2482
                        header.setCurrentBody(null);
2483
                        if (header.getBodies() != null) {
2484
                                Iterator<FileBody> it = header.getBodies().iterator();
2485
                                while(it.hasNext()){
2486
                                        FileBody bo = it.next();
2487
                                        deleteActualFile(bo.getStoredFilePath());
2488
                                        it.remove();
2489
                                        dao.delete(bo);
2490
                                }
2491
                        }
2492
                }
2493

    
2494
                dao.flush();
2495
                header.addBody(body);
2496
                header.setAuditInfo(auditInfo);
2497

    
2498
                dao.create(body);
2499
        }
2500

    
2501

    
2502
        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2503
        public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2504
                if (userId == null)
2505
                        throw new ObjectNotFoundException("No user specified");
2506
                User owner = dao.getEntityById(User.class, userId);
2507
                if(owner == null)
2508
                        throw new ObjectNotFoundException("No user specified");
2509
                long start = 0, end = 0;
2510
                if (logger.isDebugEnabled())
2511
                        start = System.currentTimeMillis();
2512
                File result = new File(generateRepositoryFilePath());
2513
                try {
2514
                        final FileOutputStream output = new FileOutputStream(result);
2515
                        final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2516
                        int n = 0;
2517

    
2518
                        while (-1 != (n = stream.read(buffer)))
2519
                                output.write(buffer, 0, n);
2520
                        output.close();
2521
                        stream.close();
2522
                } catch (IOException e) {
2523
                        if (!result.delete())
2524
                                logger.warn("Could not delete " + result.getPath());
2525
                        throw e;
2526
                }
2527
                if (logger.isDebugEnabled()) {
2528
                        end = System.currentTimeMillis();
2529
                        logger.debug("Time to upload: " + (end - start) + " (msec)");
2530
                }
2531
                return result;
2532
        }
2533

    
2534

    
2535
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2536

    
2537
                if (userId == null)
2538
                        throw new ObjectNotFoundException("No user specified");
2539
                User user = dao.getEntityById(User.class, userId);
2540
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2541
                if(status == null){
2542
                        status = new FileUploadStatus();
2543
                        status.setOwner(user);
2544
                        status.setFilename(filename);
2545
                        status.setBytesUploaded(bytesTransfered);
2546
                        status.setFileSize(fileSize);
2547
                        dao.create(status);
2548
                }
2549
                else{
2550
                        status.setBytesUploaded(bytesTransfered);
2551
                        status.setFileSize(fileSize);
2552
                        dao.update(status);
2553
                }
2554

    
2555
        }
2556

    
2557
        public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2558
                if (userId == null)
2559
                        throw new ObjectNotFoundException("No user specified");
2560
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2561
                if(status != null)
2562
                        dao.delete(status);
2563
        }
2564

    
2565
        @Override
2566
        public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2567
                return dao.getFileUploadStatus(userId, fileName);
2568
        }
2569

    
2570
        @Override
2571
        public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2572
                if (userId == null)
2573
                        throw new ObjectNotFoundException("No user specified");
2574
                if (folderId == null)
2575
                        throw new ObjectNotFoundException("No folder specified");
2576
                final User user = dao.getEntityById(User.class, userId);
2577
                final Folder folder = dao.getEntityById(Folder.class, folderId);
2578
                // Check permissions
2579
                if (!folder.hasReadPermission(user))
2580
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2581
                List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2582
                if (folder.hasReadPermission(user))
2583
                        for (Folder f : folder.getSubfolders())
2584
                                if (f.hasReadPermission(user) && !f.isDeleted())
2585
                                        subfolders.add(f.getDTO());
2586
                FolderDTO result = folder.getDTO();
2587
                result.setSubfolders(subfolders);
2588
                return folder.getDTO();
2589
        }
2590

    
2591
        @Override
2592
        public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2593
                if (userId == null)
2594
                        throw new ObjectNotFoundException("No user specified");
2595
                if (folderId == null)
2596
                        throw new ObjectNotFoundException("No folder specified");
2597
                User user = dao.getEntityById(User.class, callingUserId);
2598
                Folder folder = dao.getEntityById(Folder.class, folderId);
2599
                // Check permissions
2600
                if (!folder.hasReadPermission(user))
2601
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2602

    
2603
                FolderDTO result = folder.getDTO();
2604
                result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2605
                return result;
2606
        }
2607

    
2608
        @Override
2609
        public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2610
                        throws ObjectNotFoundException, InsufficientPermissionsException {
2611
                if (userId == null)
2612
                        throw new ObjectNotFoundException("No user specified");
2613
                if (fileId == null)
2614
                        throw new ObjectNotFoundException("No file specified");
2615
                if (version < 1)
2616
                        throw new ObjectNotFoundException("No valid version specified");
2617
                User user = dao.getEntityById(User.class, userId);
2618
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2619
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2620
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2621
                FileBody body = dao.getFileVersion(fileId, version);
2622
                return body.getDTO();
2623
        }
2624

    
2625
        @Override
2626
        public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2627
                if (userId == null)
2628
                        throw new ObjectNotFoundException("No user specified");
2629
                User user = dao.getEntityById(User.class, userId);
2630
                user.setAcceptedPolicy(isAccepted);
2631
                return user;
2632
        }
2633

    
2634
        @Override
2635
        public void updateAccounting(User user, Date date, long bandwidthDiff) {
2636
                dao.updateAccounting(user, date, bandwidthDiff);
2637
        }
2638

    
2639
        @Override
2640
        public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2641
                if (userId == null)
2642
                        throw new ObjectNotFoundException("No user specified");
2643
                if (folderId == null)
2644
                        throw new ObjectNotFoundException("No folder specified");
2645
                User user = dao.getEntityById(User.class, userId);
2646
                Folder folder = dao.getEntityById(Folder.class, folderId);
2647
                // Check permissions
2648
                if (!folder.hasReadPermission(user))
2649
                        return false;
2650
                return true;
2651
        }
2652

    
2653
        @Override
2654
        public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2655
                if (userId == null)
2656
                        throw new ObjectNotFoundException("No user specified");
2657
                User user = dao.getEntityById(User.class, userId);
2658
                user.generateWebDAVPassword();
2659
                return user.getWebDAVPassword();
2660
        }
2661

    
2662
        @Override
2663
        public Invitation findInvite(String code) {
2664
                if (code == null)
2665
                        return null;
2666
                return dao.findInvite(code);
2667
        }
2668

    
2669
        @Override
2670
        public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2671
                LDAPConnection lc = new LDAPConnection();
2672
        LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2673
        attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2674
        attributeSet.add(new LDAPAttribute("uid", username));
2675
        attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2676
        attributeSet.add(new LDAPAttribute("sn", lastname));
2677
        attributeSet.add(new LDAPAttribute("givenName", firstname));
2678
        attributeSet.add(new LDAPAttribute("mail", email));
2679
        attributeSet.add(new LDAPAttribute("userPassword", password));
2680
        String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2681
        LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2682
        try {
2683
                lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2684
                lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2685
                                getConfiguration().getString("bindPassword").getBytes("UTF8"));
2686
                lc.add(newEntry);
2687
                logger.info("Successfully added LDAP account: " + dn);
2688
                lc.disconnect();
2689
        } catch(LDAPException e) {
2690
                throw new RuntimeException(e);
2691
        } catch(UnsupportedEncodingException e) {
2692
                throw new RuntimeException(e);
2693
        }
2694

    
2695
        }
2696

    
2697
        @Override
2698
        public void upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2699
                User user = findUser(username);
2700
                if (user == null)
2701
                        throw new ObjectNotFoundException("The user was not found");
2702
                Invitation invite = findInvite(code);
2703
                if (invite.getUser() != null)
2704
                        throw new InvitationUsedException("This code has already been used");
2705
                invite.setUser(user);
2706
                user.setUserClass(getCouponUserClass());
2707
        }
2708

    
2709
        @Override
2710
        public UserClass getCouponUserClass() {
2711
                return dao.findCouponUserClass();
2712
        }
2713

    
2714
}