Statistics
| Branch: | Tag: | Revision:

root / src / gr / ebs / gss / server / ejb / ExternalAPIBean.java @ 623:66f69a7348ed

History | View | Annotate | Download (98.8 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
        @Override
190
        public User getUser(Long userId) throws ObjectNotFoundException {
191
                if (userId == null)
192
                        throw new ObjectNotFoundException("No user specified");
193
                return dao.getEntityById(User.class, userId);
194
        }
195

    
196
        @Override
197
        public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
198
                return getUser(userId).getDTO();
199
        }
200

    
201
        @Override
202
        public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
203
                if (groupId == null)
204
                        throw new ObjectNotFoundException("No group specified");
205
                final Group group = dao.getEntityById(Group.class, groupId);
206
                return group.getDTO();
207
        }
208

    
209
        @Override
210
        public GroupDTO getGroup(Long userId, String name) throws ObjectNotFoundException {
211
                if (userId == null)
212
                        throw new ObjectNotFoundException("No user specified");
213
                if (name == null)
214
                        throw new ObjectNotFoundException("No group specified");
215
                User user = dao.getEntityById(User.class, userId);
216
                List<Group> groups = user.getGroupsSpecified();
217
                for (Group group: groups)
218
                        if (group.getName().equals(name))
219
                                return group.getDTO();
220
                throw new ObjectNotFoundException("Group " + name + " not found");
221
        }
222

    
223
        @Override
224
        public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
225
                if (userId == null)
226
                        throw new ObjectNotFoundException("No user specified");
227
                final List<Group> groups = dao.getGroups(userId);
228
                final List<GroupDTO> result = new ArrayList<GroupDTO>();
229
                for (final Group g : groups)
230
                        result.add(g.getDTO());
231
                return result;
232
        }
233

    
234
        @Override
235
        public List<FileHeaderDTO> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
236
                        throws ObjectNotFoundException, InsufficientPermissionsException {
237
                // Validate.
238
                if (userId == null)
239
                        throw new ObjectNotFoundException("No user specified");
240
                if (folderId == null)
241
                        throw new ObjectNotFoundException("No folder specified");
242
                User user = dao.getEntityById(User.class, userId);
243
                Folder folder = dao.getEntityById(Folder.class, folderId);
244
                if (!folder.hasReadPermission(user))
245
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
246
                // Do the actual work.
247
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
248
                List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
249
                for (FileHeader f : files)
250
                        result.add(f.getDTO());
251
                return result;
252
        }
253

    
254
        @Override
255
        public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
256
                // Validate.
257
                if (userId == null)
258
                        throw new ObjectNotFoundException("No user specified");
259
                if (groupId == null)
260
                        throw new ObjectNotFoundException("No group specified");
261

    
262
                // Do the actual work.
263
                final List<User> users = dao.getUsers(groupId);
264
                final List<UserDTO> result = new ArrayList<UserDTO>();
265
                for (final User u : users)
266
                        result.add(u.getDTO());
267
                return result;
268
        }
269

    
270
        @Override
271
        public FolderDTO createFolder(Long userId, Long parentId, String name)
272
                        throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
273
                // Validate.
274
                if (userId == null)
275
                        throw new ObjectNotFoundException("No user specified");
276
                if (StringUtils.isEmpty(name))
277
                        throw new ObjectNotFoundException("New folder name is empty");
278
                if (parentId == null)
279
                        throw new ObjectNotFoundException("No parent specified");
280
                if (dao.existsFolderOrFile(parentId, name))
281
                        throw new DuplicateNameException("A folder or file with the name '" +
282
                                                name + "' already exists at this level");
283

    
284
                User creator = dao.getEntityById(User.class, userId);
285

    
286
                Folder parent = null;
287
                try {
288
                        parent = dao.getEntityById(Folder.class, parentId);
289
                } catch (ObjectNotFoundException onfe) {
290
                        // Supply a more accurate problem description.
291
                        throw new ObjectNotFoundException("Parent folder not found");
292
                }
293
                if (!parent.hasWritePermission(creator))
294
                        throw new InsufficientPermissionsException("You don't have the permissions" +
295
                                        " to write to this folder");
296

    
297
                // Do the actual work.
298
                return createFolder(name, parent, creator);
299
        }
300

    
301
        /**
302
         * Create a new folder with the provided name, parent and owner.
303
         *
304
         * @param name
305
         * @param parent
306
         * @param creator
307
         * @return the new folder
308
         */
309
        private FolderDTO createFolder(String name, Folder parent, User creator) {
310
                Folder folder = new Folder();
311
                folder.setName(name);
312
                if (parent != null) {
313
                        parent.addSubfolder(folder);
314
                        folder.setOwner(parent.getOwner());
315
                } else
316
                        folder.setOwner(creator);
317

    
318
                Date now = new Date();
319
                AuditInfo auditInfo = new AuditInfo();
320
                auditInfo.setCreatedBy(creator);
321
                auditInfo.setCreationDate(now);
322
                auditInfo.setModifiedBy(creator);
323
                auditInfo.setModificationDate(now);
324
                folder.setAuditInfo(auditInfo);
325
                touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
326

    
327
                if (parent != null)
328
                        for (Permission p : parent.getPermissions()) {
329
                                Permission permission = new Permission();
330
                                permission.setGroup(p.getGroup());
331
                                permission.setUser(p.getUser());
332
                                permission.setRead(p.getRead());
333
                                permission.setWrite(p.getWrite());
334
                                permission.setModifyACL(p.getModifyACL());
335
                                folder.addPermission(permission);
336
                        }
337
                else {
338
                        Permission permission = new Permission();
339
                        permission.setUser(creator);
340
                        permission.setRead(true);
341
                        permission.setWrite(true);
342
                        permission.setModifyACL(true);
343
                        folder.addPermission(permission);
344
                }
345
                dao.create(folder);
346
                return folder.getDTO();
347
        }
348

    
349
        @Override
350
        public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
351
                // Validate.
352
                if (userId == null)
353
                        throw new ObjectNotFoundException("No user specified");
354
                if (folderId == null)
355
                        throw new ObjectNotFoundException("No folder specified");
356

    
357
                // Do the actual work.
358
                final Folder folder = dao.getEntityById(Folder.class, folderId);
359
                final Folder parent = folder.getParent();
360
                if (parent == null)
361
                        throw new ObjectNotFoundException("Deleting the root folder is not allowed");
362
                final User user = dao.getEntityById(User.class, userId);
363
                if (!folder.hasDeletePermission(user)) {
364
                        logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
365
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
366
                }
367
                removeSubfolderFiles(folder);
368
                parent.removeSubfolder(folder);
369
                dao.delete(folder);
370
                touchParentFolders(parent, user, new Date());
371
        }
372

    
373
        /**
374
         * Traverses the folder and deletes all actual files (file system)
375
         * regardless of permissions
376
         *
377
         * @param folder
378
         */
379
        private void removeSubfolderFiles(Folder folder) {
380
                //remove files for all subfolders
381
                for (Folder subfolder:folder.getSubfolders())
382
                        removeSubfolderFiles(subfolder);
383
                //remove this folder's file bodies (actual files)
384
                for (FileHeader file:folder.getFiles()) {
385
                        for (FileBody body:file.getBodies())
386
                                deleteActualFile(body.getStoredFilePath());
387
                        indexFile(file.getId(), true);
388
                }
389
        }
390

    
391
        @Override
392
        @SuppressWarnings("unchecked")
393
        public List<FolderDTO> getSubfolders(Long userId, Long folderId)
394
                        throws ObjectNotFoundException, InsufficientPermissionsException {
395
                if (userId == null)
396
                        throw new ObjectNotFoundException("No user specified");
397
                if (folderId == null)
398
                        throw new ObjectNotFoundException("No folder specified");
399
                User user = dao.getEntityById(User.class, userId);
400
                Folder folder = dao.getEntityById(Folder.class, folderId);
401
                if (!folder.hasReadPermission(user))
402
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
403
                List<FolderDTO> result = new ArrayList<FolderDTO>();
404
                if (folder.hasReadPermission(user))
405
                        for (Folder f : folder.getSubfolders())
406
                                if (f.hasReadPermission(user) && !f.isDeleted())
407
                                        result.add(f.getDTO());
408
                return result;
409
        }
410

    
411
        @Override
412
        public FolderDTO updateFolder(Long userId, Long folderId, String folderName,
413
                                Set<PermissionDTO> permissions)
414
                        throws InsufficientPermissionsException, ObjectNotFoundException,
415
                        DuplicateNameException {
416

    
417
                // Validate.
418
                if (userId == null)
419
                        throw new ObjectNotFoundException("No user specified");
420
                if (folderId == null)
421
                        throw new ObjectNotFoundException("No folder specified");
422

    
423
                Folder folder = dao.getEntityById(Folder.class, folderId);
424
                User user = dao.getEntityById(User.class, userId);
425
                if (folderName != null && !folder.hasWritePermission(user))
426
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
427
                if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
428
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
429

    
430
                Folder parent = folder.getParent();
431
                if (folderName != null) {
432
                        if (parent != null)
433
                                if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
434
                                        throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
435

    
436
                        // Do the actual modification.
437
                        folder.setName(folderName);
438
                }
439
                if (permissions != null)
440
                        setFolderPermissions(user, folder, permissions);
441

    
442
                folder.getAuditInfo().setModificationDate(new Date());
443
                folder.getAuditInfo().setModifiedBy(user);
444
                dao.update(folder);
445
                touchParentFolders(folder, user, new Date());
446
                return folder.getDTO();
447
        }
448

    
449
        @Override
450
        public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
451
                // Validate.
452
                if (userId == null)
453
                        throw new ObjectNotFoundException("No user specified");
454
                if (StringUtils.isEmpty(name))
455
                        throw new ObjectNotFoundException("New group name is empty");
456
                if (name.indexOf('/')>=0)
457
                        throw new IllegalArgumentException("Character '/' is not allowed in group name");
458
                if (dao.existsGroup(userId, name))
459
                        throw new DuplicateNameException("A group with the name '" + name + "' already exists");
460

    
461
                // TODO: Check permissions
462

    
463
                final User owner = dao.getEntityById(User.class, userId);
464

    
465
                // Do the actual work.
466
                owner.createGroup(name);
467
        }
468

    
469
        @Override
470
        public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
471
                // Validate.
472
                if (userId == null)
473
                        throw new ObjectNotFoundException("No user specified");
474
                if (groupId == null)
475
                        throw new ObjectNotFoundException("No group specified");
476

    
477
                // Do the actual work.
478
                final User owner = dao.getEntityById(User.class, userId);
479
                final Group group = dao.getEntityById(Group.class, groupId);
480
                // Only delete the group if actually owned by the user.
481
                if (group.getOwner().equals(owner)) {
482
                        List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
483
                        for (Folder f : folders){
484
                                f.getPermissions().removeAll(group.getPermissions());
485
                                for(FileHeader file : f.getFiles())
486
                                        file.getPermissions().removeAll(group.getPermissions());
487
                        }
488
                        List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
489
                        for(FileHeader h : files)
490
                                h.getPermissions().removeAll(group.getPermissions());
491
                        owner.removeSpecifiedGroup(group);
492
                        dao.delete(group);
493
                }
494
                else throw new InsufficientPermissionsException("You are not the owner of this group");
495
        }
496

    
497
        @Override
498
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
499
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
500
                        InsufficientPermissionsException, QuotaExceededException {
501
                File file = null;
502
                try {
503
                        file = uploadFile(stream, userId);
504
                } catch ( IOException ioe) {
505
                        // Supply a more accurate problem description.
506
                        throw new GSSIOException("Problem creating file",ioe);
507
                }
508
                return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
509
        }
510

    
511
        /* (non-Javadoc)
512
         * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
513
         */
514
        @Override
515
        public void indexFile(Long fileId, boolean delete) {
516
                Connection qConn = null;
517
                Session session = null;
518
                MessageProducer sender = null;
519
                try {
520
                        Context jndiCtx = new InitialContext();
521
                        ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
522
                        Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
523
                        qConn = factory.createConnection();
524
                        session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
525
                        sender = session.createProducer(queue);
526

    
527
                        MapMessage map = session.createMapMessage();
528
                        map.setObject("id", fileId);
529
                        map.setBoolean("delete", delete);
530
                        sender.send(map);
531
                }
532
                catch (NamingException e) {
533
                        logger.error("Index was not updated: ", e);
534
                }
535
                catch (JMSException e) {
536
                        logger.error("Index was not updated: ", e);
537
                }
538
                finally {
539
                        try {
540
                                if (sender != null)
541
                                        sender.close();
542
                                if (session != null)
543
                                        session.close();
544
                                if (qConn != null)
545
                                        qConn.close();
546
                        }
547
                        catch (JMSException e) {
548
                                logger.warn(e);
549
                        }
550
                }
551
        }
552

    
553

    
554

    
555
        /**
556
         * A helper method that generates a unique file path for a stored file. The
557
         * files are stored using random hash names that are distributed evenly in
558
         * a 2-level tree of subdirectories named after the first two hex characters
559
         * in the name. For example, file ab1234cd5769f will be stored in the path
560
         * /file-repository-root/a/b/ab1234cd5769f. The directories will be created
561
         * if they don't already exist.
562
         *
563
         * @return a unique new file path
564
         */
565
        private String generateRepositoryFilePath() {
566
                String filename = Long.toHexString(random.nextLong());
567
                String fileRepositoryPath = getConfiguration().getString("fileRepositoryPath","/tmp");
568
                File root = new File(fileRepositoryPath);
569
                if (!root.exists())
570
                        root.mkdirs();
571
                File firstFolder = new File(root + File.separator + filename.substring(0, 1));
572
                if (!firstFolder.exists())
573
                        firstFolder.mkdir();
574
                File secondFolder = new File(firstFolder + File.separator + filename.substring(1, 2));
575
                if (!secondFolder.exists())
576
                        secondFolder.mkdir();
577
                return secondFolder + File.separator + filename;
578
        }
579

    
580
        @Override
581
        public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
582
                // Validate.
583
                if (userId == null)
584
                        throw new ObjectNotFoundException("No user specified");
585
                if (fileId == null)
586
                        throw new ObjectNotFoundException("No file specified");
587

    
588
                // Do the actual work.
589
                final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
590
                final Folder parent = file.getFolder();
591
                if (parent == null)
592
                        throw new ObjectNotFoundException("The specified file has no parent folder");
593
                final User user = dao.getEntityById(User.class, userId);
594
                if (!file.hasDeletePermission(user))
595
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
596
                for (final FileBody body : file.getBodies())
597
                        deleteActualFile(body.getStoredFilePath());
598
                dao.delete(file);
599
                touchParentFolders(parent, user, new Date());
600
                indexFile(fileId, true);
601
        }
602

    
603
        @Override
604
        public void deleteActualFile(String path) {
605
                if (path == null)
606
                        return;
607
                File file = new File(path);
608
                if (!file.delete())
609
                        logger.error("Could not delete file " + path);
610
        }
611

    
612
        @Override
613
        public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
614
                if (userId == null)
615
                        throw new ObjectNotFoundException("No user specified");
616
                if (fileHeaderId == null)
617
                        throw new ObjectNotFoundException("No file specified");
618
                if (StringUtils.isEmpty(tag))
619
                        throw new ObjectNotFoundException("Tag is empty");
620

    
621
                final User user = dao.getEntityById(User.class, userId);
622
                final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
623
                final Folder parent = fh.getFolder();
624
                if (parent == null)
625
                        throw new ObjectNotFoundException("The specified file has no parent folder");
626
                user.addTag(fh, tag);
627
                touchParentFolders(parent, user, new Date());
628
        }
629

    
630
        @Override
631
        public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
632
                return dao.getUserTags(userId);
633
        }
634

    
635
        @Override
636
        public void updateFile(Long userId, Long fileId, String name,
637
                                String tagSet, Date modificationDate, Boolean versioned,
638
                                Boolean readForAll,        Set<PermissionDTO> permissions)
639
                        throws DuplicateNameException, ObjectNotFoundException,        InsufficientPermissionsException {
640
                if (userId == null)
641
                        throw new ObjectNotFoundException("No user specified");
642
                if (fileId == null)
643
                        throw new ObjectNotFoundException("No file specified");
644
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
645
                final Folder parent = file.getFolder();
646
                if (parent == null)
647
                        throw new ObjectNotFoundException("The specified file has no parent folder");
648

    
649
                User user = dao.getEntityById(User.class, userId);
650
                // Check permissions for modifying the file metadata.
651
                if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
652
                        throw new InsufficientPermissionsException("User " + user.getId() +        " cannot update file " + file.getName() + "(" +        file.getId() + ")");
653
                // Check permissions for making file public.
654
                if (readForAll != null && !user.equals(file.getOwner()))
655
                                throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
656
                // Check permissions for modifying the ACL.
657
                if(permissions != null && !permissions.isEmpty() &&        !file.hasModifyACLPermission(user))
658
                        throw new InsufficientPermissionsException("User " + user.getId() +        " cannot update the permissions on file " +        file.getName() + "(" + file.getId() + ")");
659

    
660
                if (name != null) {
661
                        // Do plain check for file already exists.
662
                        // Extreme concurrency case should be caught by constraint violation later.
663
                        if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
664
                        file.setName(name);
665
                }
666

    
667
                if (modificationDate != null)
668
                        file.getAuditInfo().setModificationDate(modificationDate);
669
                else
670
                        file.getAuditInfo().setModificationDate(new Date());
671
                file.getAuditInfo().setModifiedBy(user);
672

    
673
                List<FileTag> tags = file.getFileTags();
674
                if (tagSet != null) {
675
                        Iterator<FileTag> i = tags.iterator();
676
                        while (i.hasNext()) {
677
                                FileTag tag = i.next();
678
                                i.remove();
679
                                tag.setFile(null);
680
                                user.removeTag(tag);
681
                                dao.delete(tag);
682
                        }
683
                        dao.flush();
684
                        StringTokenizer st = new StringTokenizer(tagSet, ",");
685
                        while (st.hasMoreTokens())
686
                                new FileTag(user, file, st.nextToken().trim());
687
                }
688
                if (versioned != null && !file.isVersioned() == versioned) {
689
                        if (file.isVersioned())
690
                                removeOldVersions(userId, fileId);
691
                        file.setVersioned(versioned);
692
                }
693
                if (readForAll != null && user.equals(file.getOwner()))
694
                        file.setReadForAll(readForAll);
695
                if (permissions != null && !permissions.isEmpty())
696
                        setFilePermissions(file, permissions);
697

    
698
                /*
699
                 * Force constraint violation to manifest itself here.
700
                 * This should cover extreme concurrency cases that the simple check
701
                 * above hasn't caught.
702
                 */
703
                try {
704
                        dao.flush();
705
                }
706
                catch (EJBTransactionRolledbackException e) {
707
                        Throwable cause = e.getCause();
708
                        if (cause instanceof PersistenceException && cause.getCause() instanceof ConstraintViolationException)
709
                                throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
710
                        throw e;
711
                }
712

    
713
                touchParentFolders(parent, user, new Date());
714

    
715
                // Re-index the file if it was modified.
716
                if (name != null || tagSet != null)
717
                        indexFile(fileId, false);
718
        }
719

    
720
        @Override
721
        public InputStream getFileContents(Long userId, Long fileId)
722
                        throws ObjectNotFoundException, InsufficientPermissionsException {
723
                if (userId == null)
724
                        throw new ObjectNotFoundException("No user specified");
725
                if (fileId == null)
726
                        throw new ObjectNotFoundException("No file specified");
727

    
728
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
729
                User user = dao.getEntityById(User.class, userId);
730
                if (!header.hasReadPermission(user)) {
731
                        logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
732
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
733
                }
734

    
735
                File f = new File(header.getCurrentBody().getStoredFilePath());
736
                try {
737
                        return new FileInputStream(f);
738
                } catch (FileNotFoundException e) {
739
                        logger.error("Could not locate the contents of file " + f.getAbsolutePath());
740
                        throw new ObjectNotFoundException("The file contents could not be located");
741
                }
742
        }
743

    
744
        /* (non-Javadoc)
745
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
746
         */
747
        @Override
748
        public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
749
                if (userId == null)
750
                        throw new ObjectNotFoundException("No user specified");
751
                if (fileId == null)
752
                        throw new ObjectNotFoundException("No file specified");
753
                if (bodyId == null)
754
                        throw new ObjectNotFoundException("No file specified");
755

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

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

    
773
        @Override
774
        public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
775
                if (userId == null)
776
                        throw new ObjectNotFoundException("No user specified");
777
                if (fileId == null)
778
                        throw new ObjectNotFoundException("No file specified");
779
                final User user = dao.getEntityById(User.class, userId);
780
                final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
781
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
782
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
783
                return file.getDTO();
784
        }
785

    
786
        @Override
787
        public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
788
                if (userId == null)
789
                        throw new ObjectNotFoundException("No user specified");
790
                if (fileId == null)
791
                        throw new ObjectNotFoundException("No file specified");
792
                User user = dao.getEntityById(User.class, userId);
793
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
794
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
795
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
796
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
797
                return body.getDTO();
798
        }
799

    
800
        @Override
801
        public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
802
                        throws ObjectNotFoundException {
803
                if (ownerId == null)
804
                        throw new ObjectNotFoundException("No user specified");
805
                if (StringUtils.isEmpty(path))
806
                        throw new ObjectNotFoundException("No path specified");
807

    
808
                User owner = dao.getEntityById(User.class, ownerId);
809
                List<String> pathElements = new ArrayList<String>();
810
                StringTokenizer st = new StringTokenizer(path, "/");
811
                while (st.hasMoreTokens())
812
                        pathElements.add(st.nextToken());
813
                if (pathElements.size() < 1)
814
                        return getRootFolder(owner.getId());
815
                // Store the last element, since it requires special handling.
816
                String lastElement = pathElements.remove(pathElements.size() - 1);
817
                FolderDTO cursor = getRootFolder(owner.getId());
818
                // Traverse and verify the specified folder path.
819
                for (String pathElement : pathElements) {
820
                        cursor = getFolder(cursor.getId(), pathElement);
821
                        if (cursor.isDeleted())
822
                                throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
823
                }
824

    
825
                // Use the lastElement to retrieve the actual resource.
826
                Object resource = null;
827
                try {
828
                        FileHeaderDTO file = getFile(cursor.getId(), lastElement);
829
                        if (ignoreDeleted && file.isDeleted())
830
                                throw new ObjectNotFoundException("Resource not found");
831
                        resource = file;
832
                } catch (ObjectNotFoundException e) {
833
                        // Perhaps the requested resource is not a file, so
834
                        // check for folders as well.
835
                        FolderDTO folder = getFolder(cursor.getId(), lastElement);
836
                        if (ignoreDeleted && folder.isDeleted())
837
                                throw new ObjectNotFoundException("Resource not found");
838
                        resource = folder;
839
                }
840
                return resource;
841
        }
842

    
843
        /**
844
         * Retrieve a file for the specified user that has the specified name and
845
         * its parent folder has id equal to folderId.
846
         *
847
         * @param userId the ID of the current user
848
         * @param folderId the ID of the parent folder
849
         * @param name the name of the requested file
850
         * @return the file found
851
         * @throws ObjectNotFoundException if the specified folder or file was not
852
         *             found, with the exception message mentioning the precise
853
         *             problem
854
         */
855
        private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
856
                if (folderId == null)
857
                        throw new ObjectNotFoundException("No parent folder specified");
858
                if (StringUtils.isEmpty(name))
859
                        throw new ObjectNotFoundException("No file specified");
860

    
861
                FileHeader file = dao.getFile(folderId, name);
862
                return file.getDTO();
863
        }
864

    
865
        /**
866
         * Retrieve a folder for the specified user that has the specified name and
867
         * its parent folder has id equal to parentId.
868
         *
869
         * @param parentId the ID of the parent folder
870
         * @param name the name of the requested folder
871
         * @return the folder found
872
         * @throws ObjectNotFoundException if the specified folder or parent was not
873
         *             found, with the exception message mentioning the precise
874
         *             problem
875
         */
876
        private FolderDTO getFolder(Long parentId, String name) throws ObjectNotFoundException {
877
                if (parentId == null)
878
                        throw new ObjectNotFoundException("No parent folder specified");
879
                if (StringUtils.isEmpty(name))
880
                        throw new ObjectNotFoundException("No folder specified");
881

    
882
                Folder folder = dao.getFolder(parentId, name);
883
                return folder.getDTO();
884
        }
885

    
886
        private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
887
                File file = null;
888
                try {
889
                        file = uploadFile(resourceInputStream, userId);
890
                } catch ( IOException ioe) {
891
                        // Supply a more accurate problem description.
892
                        throw new GSSIOException("Problem creating file",ioe);
893
                }
894
                return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
895
        }
896

    
897
        @Override
898
        public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
899
                if (userId == null)
900
                        throw new ObjectNotFoundException("No user specified");
901
                if (fileId == null)
902
                        throw new ObjectNotFoundException("No file specified");
903
                if (StringUtils.isEmpty(dest))
904
                        throw new ObjectNotFoundException("No destination specified");
905

    
906
                Object destination = getResourceAtPath(userId, getParentPath(dest), true);
907
                if (!(destination instanceof FolderDTO))
908
                        throw new ObjectNotFoundException("Destination parent folder not found");
909
                FolderDTO parent = (FolderDTO) destination;
910
                copyFile(userId, fileId, parent.getId(), getLastElement(dest));
911
        }
912

    
913
        @Override
914
        public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
915
                if (userId == null)
916
                        throw new ObjectNotFoundException("No user specified");
917
                if (ownerId == null)
918
                        throw new ObjectNotFoundException("No owner specified");
919
                if (fileId == null)
920
                        throw new ObjectNotFoundException("No file specified");
921
                if (StringUtils.isEmpty(dest))
922
                        throw new ObjectNotFoundException("No destination specified");
923

    
924
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
925
                if (!(destination instanceof FolderDTO))
926
                        throw new ObjectNotFoundException("Destination parent folder not found");
927
                FolderDTO parent = (FolderDTO) destination;
928
                copyFile(userId, fileId, parent.getId(), getLastElement(dest));
929
        }
930

    
931
        @Override
932
        public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
933
                if (userId == null)
934
                        throw new ObjectNotFoundException("No user specified");
935
                if (fileId == null)
936
                        throw new ObjectNotFoundException("No file specified");
937
                if (destId == null)
938
                        throw new ObjectNotFoundException("No destination specified");
939
                if (StringUtils.isEmpty(destName))
940
                        throw new ObjectNotFoundException("No destination file name specified");
941

    
942
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
943
                Folder destination = dao.getEntityById(Folder.class, destId);
944
                User user = dao.getEntityById(User.class, userId);
945
                if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
946
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
947
                boolean versioned = file.isVersioned();
948
                int versionsNumber = file.getBodies().size();
949
                FileBody oldestBody = file.getBodies().get(0);
950
                assert oldestBody != null;
951
                File contents = new File(oldestBody.getStoredFilePath());
952
                try {
953
                        createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
954
                        FileHeader copiedFile = dao.getFile(destination.getId(), destName);
955
                        copiedFile.setVersioned(versioned);
956
                        dao.flush();
957
                        if (versionsNumber > 1)
958
                                for (int i = 1; i < versionsNumber; i++) {
959
                                        FileBody body = file.getBodies().get(i);
960
                                        assert body != null;
961
                                        contents = new File(body.getStoredFilePath());
962
                                        updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
963
                                }
964
                        List<FileTag> tags = file.getFileTags();
965
                        for (FileTag tag : tags)
966
                                createTag(userId, copiedFile.getId(), tag.getTag());
967

    
968
                } catch (FileNotFoundException e) {
969
                        throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
970
                }
971

    
972
        }
973

    
974
        @Override
975
        public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
976
                if (userId == null)
977
                        throw new ObjectNotFoundException("No user specified");
978
                if (folderId == null)
979
                        throw new ObjectNotFoundException("No folder specified");
980
                if (StringUtils.isEmpty(dest))
981
                        throw new ObjectNotFoundException("No destination specified");
982

    
983
                Object destination = getResourceAtPath(userId, getParentPath(dest), true);
984
                if (!(destination instanceof FolderDTO))
985
                        throw new ObjectNotFoundException("Destination folder not found");
986
                FolderDTO parent = (FolderDTO) destination;
987
                copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
988
        }
989

    
990
        @Override
991
        public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
992
                if (userId == null)
993
                        throw new ObjectNotFoundException("No user specified");
994
                if (folderId == null)
995
                        throw new ObjectNotFoundException("No folder specified");
996
                if (destId == null)
997
                        throw new ObjectNotFoundException("No destination specified");
998
                if (StringUtils.isEmpty(destName))
999
                        throw new ObjectNotFoundException("No destination folder name specified");
1000
                Folder folder = dao.getEntityById(Folder.class, folderId);
1001
                Folder destination = dao.getEntityById(Folder.class, destId);
1002
                User user = dao.getEntityById(User.class, userId);
1003
                if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1004
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1005
                createFolder(user.getId(), destination.getId(), destName);
1006
        }
1007

    
1008
        @Override
1009
        public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1010
                if (userId == null)
1011
                        throw new ObjectNotFoundException("No user specified");
1012
                if (ownerId == null)
1013
                        throw new ObjectNotFoundException("No owner specified");
1014
                if (folderId == null)
1015
                        throw new ObjectNotFoundException("No folder specified");
1016
                if (StringUtils.isEmpty(dest))
1017
                        throw new ObjectNotFoundException("No destination specified");
1018

    
1019
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1020
                if (!(destination instanceof FolderDTO))
1021
                        throw new ObjectNotFoundException("Destination folder not found");
1022
                FolderDTO parent = (FolderDTO) destination;
1023
                copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1024
        }
1025

    
1026
        @Override
1027
        public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1028
                if (userId == null)
1029
                        throw new ObjectNotFoundException("No user specified");
1030
                if (folderId == null)
1031
                        throw new ObjectNotFoundException("No folder specified");
1032
                if (destId == null)
1033
                        throw new ObjectNotFoundException("No destination specified");
1034
                if (StringUtils.isEmpty(destName))
1035
                        throw new ObjectNotFoundException("No destination folder name specified");
1036

    
1037
                Folder folder = dao.getEntityById(Folder.class, folderId);
1038
                Folder destination = dao.getEntityById(Folder.class, destId);
1039
                final User user = dao.getEntityById(User.class, userId);
1040
                // XXX: quick fix need to copy only visible items to user (Source
1041
                // for bugs)
1042
                if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1043
                        return;
1044
                if(folder.isDeleted())//do not copy trashed folder and contents
1045
                        return;
1046
                if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1047
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1048
                createFolder(user.getId(), destination.getId(), destName);
1049
                Folder createdFolder = dao.getFolder(destination.getId(), destName);
1050
                List<FileHeader> files = folder.getFiles();
1051
                if (files != null)
1052
                        for (FileHeader file : files)
1053
                                if(!file.isDeleted())
1054
                                        copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1055
                List<Folder> subFolders = folder.getSubfolders();
1056
                if (subFolders != null)
1057
                        for (Folder sub : subFolders)
1058
                                if(!sub.getId().equals(createdFolder.getId()))
1059
                                        copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1060

    
1061
        }
1062

    
1063
        /**
1064
         * For a provided path, remove the last element and return the rest, that is
1065
         * the path of the parent folder.
1066
         *
1067
         * @param path the specified path
1068
         * @return the path of the parent folder
1069
         * @throws ObjectNotFoundException if the provided string contains no path
1070
         *             delimiters
1071
         */
1072
        private String getParentPath(String path) throws ObjectNotFoundException {
1073
                int lastDelimiter = path.lastIndexOf('/');
1074
                if (lastDelimiter == 0)
1075
                        return "/";
1076
                if (lastDelimiter == -1)
1077
                        // No path found.
1078
                        throw new ObjectNotFoundException("There is no parent in the path: " + path);
1079
                else if (lastDelimiter < path.length() - 1)
1080
                        // Return the part before the delimiter.
1081
                        return path.substring(0, lastDelimiter);
1082
                else {
1083
                        // Remove the trailing delimiter and then recurse.
1084
                        String strippedTrail = path.substring(0, lastDelimiter);
1085
                        return getParentPath(strippedTrail);
1086
                }
1087
        }
1088

    
1089
        /**
1090
         * Get the last element in a path that denotes the file or folder name.
1091
         *
1092
         * @param path the provided path
1093
         * @return the last element in the path
1094
         */
1095
        private String getLastElement(String path) {
1096
                int lastDelimiter = path.lastIndexOf('/');
1097
                if (lastDelimiter == -1)
1098
                        // No path found.
1099
                        return path;
1100
                else if (lastDelimiter < path.length() - 1)
1101
                        // Return the part after the delimiter.
1102
                        return path.substring(lastDelimiter + 1);
1103
                else {
1104
                        // Remove the trailing delimiter and then recurse.
1105
                        String strippedTrail = path.substring(0, lastDelimiter);
1106
                        return getLastElement(strippedTrail);
1107
                }
1108
        }
1109

    
1110
        @Override
1111
        public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1112
                if (userId == null)
1113
                        throw new ObjectNotFoundException("No user specified");
1114
                if (fileId == null)
1115
                        throw new ObjectNotFoundException("No file specified");
1116

    
1117
                // Do the actual work.
1118
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1119
                Folder parent = file.getFolder();
1120
                if (parent == null)
1121
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1122
                User user = dao.getEntityById(User.class, userId);
1123
                if (!file.hasDeletePermission(user))
1124
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1125

    
1126
                file.setDeleted(true);
1127
                dao.update(file);
1128
                touchParentFolders(parent, user, new Date());
1129
        }
1130

    
1131
        @Override
1132
        public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1133
                if (userId == null)
1134
                        throw new ObjectNotFoundException("No user specified");
1135
                if (ownerId == null)
1136
                        throw new ObjectNotFoundException("No owner specified");
1137
                if (fileId == null)
1138
                        throw new ObjectNotFoundException("No file specified");
1139
                if (StringUtils.isEmpty(dest))
1140
                        throw new ObjectNotFoundException("No destination specified");
1141

    
1142
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1143
                if (!(destination instanceof FolderDTO))
1144
                        throw new ObjectNotFoundException("Destination parent folder not found");
1145
                FolderDTO parent = (FolderDTO) destination;
1146
                moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1147
        }
1148

    
1149
        @Override
1150
        public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1151
                if (userId == null)
1152
                        throw new ObjectNotFoundException("No user specified");
1153
                if (fileId == null)
1154
                        throw new ObjectNotFoundException("No file specified");
1155
                if (destId == null)
1156
                        throw new ObjectNotFoundException("No destination specified");
1157
                if (StringUtils.isEmpty(destName))
1158
                        throw new ObjectNotFoundException("No destination file name specified");
1159

    
1160
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1161
                Folder source = file.getFolder();
1162
                Folder destination = dao.getEntityById(Folder.class, destId);
1163

    
1164
                User owner = dao.getEntityById(User.class, userId);
1165
                if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1166
                        throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1167

    
1168
                // if the destination folder belongs to another user:
1169
                if (!file.getOwner().equals(destination.getOwner())) {
1170
                        // (a) check if the destination quota allows the move
1171
                        if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1172
                                throw new QuotaExceededException("Not enough free space available");
1173
                        User newOwner = destination.getOwner();
1174
                        // (b) if quota OK, change the owner of the file
1175
                        file.setOwner(newOwner);
1176
                        // if the file has no permission for the new owner, add it
1177
                        Permission ownerPermission = null;
1178
                        for (final Permission p : file.getPermissions())
1179
                                if (p.getUser() != null)
1180
                                        if (p.getUser().equals(newOwner)) {
1181
                                                ownerPermission = p;
1182
                                                break;
1183
                                        }
1184
                        if (ownerPermission == null) {
1185
                                ownerPermission = new Permission();
1186
                                ownerPermission.setUser(newOwner);
1187
                                file.addPermission(ownerPermission);
1188
                        }
1189
                        ownerPermission.setRead(true);
1190
                        ownerPermission.setWrite(true);
1191
                        ownerPermission.setModifyACL(true);
1192
                }
1193
                // move the file to the destination folder
1194
                file.setFolder(destination);
1195
                touchParentFolders(source, owner, new Date());
1196
                touchParentFolders(destination, owner, new Date());
1197
        }
1198

    
1199
        @Override
1200
        public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1201
                if (userId == null)
1202
                        throw new ObjectNotFoundException("No user specified");
1203
                if (ownerId == null)
1204
                        throw new ObjectNotFoundException("No owner specified");
1205
                if (folderId == null)
1206
                        throw new ObjectNotFoundException("No folder specified");
1207
                if (StringUtils.isEmpty(dest))
1208
                        throw new ObjectNotFoundException("No destination specified");
1209

    
1210
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1211
                if (!(destination instanceof FolderDTO))
1212
                        throw new ObjectNotFoundException("Destination parent folder not found");
1213
                FolderDTO parent = (FolderDTO) destination;
1214
                moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1215
        }
1216

    
1217
        @Override
1218
        public void moveFolder(Long userId, Long folderId, Long destId, String destName)
1219
                        throws ObjectNotFoundException, InsufficientPermissionsException,
1220
                        QuotaExceededException {
1221
                Folder source = dao.getEntityById(Folder.class, folderId);
1222
                Folder destination = dao.getEntityById(Folder.class, destId);
1223
                User user = dao.getEntityById(User.class, userId);
1224
                User sourceOwner = source.getOwner();
1225
                User destinationOwner = destination.getOwner();
1226
                // Do not move trashed folders and contents.
1227
                if (source.isDeleted())
1228
                        return;
1229
                // Check permissions.
1230
                if (!destination.hasWritePermission(user)
1231
                                || !source.hasReadPermission(user)
1232
                                || !source.hasWritePermission(user))
1233
                        throw new InsufficientPermissionsException("You don't have the " +
1234
                                        "necessary permissions");
1235
                // Use the same timestamp for all subsequent modifications to make
1236
                // changes appear simultaneous.
1237
                Date now = new Date();
1238
                // If source and destination are not in the same user's namespace,
1239
                // change owners and check quota.
1240
                if (!sourceOwner.equals(destinationOwner)) {
1241
                        changeOwner(source, destinationOwner, user, now);
1242
                        if (getQuotaLeft(destinationOwner.getId()) < 0)
1243
                                throw new QuotaExceededException("Not enough free space " +
1244
                                                "available in destination folder");
1245
                }
1246
                // Perform the move.
1247
                Folder oldParent = source.getParent();
1248
                oldParent.removeSubfolder(source);
1249
                destination.addSubfolder(source);
1250
                // Mark the former parent and destination trees upwards as modified.
1251
                touchParentFolders(oldParent, user, now);
1252
                touchParentFolders(source, user, now);
1253
        }
1254

    
1255
        /**
1256
         * Recursively change the owner of the specified folder and all of its
1257
         * contents to the specified owner. Also mark them all as modified with the
1258
         * specified modifier and modificationDate.
1259
         */
1260
        private void changeOwner(Folder folder, User owner, User modifier, Date modificationDate) {
1261
                for (FileHeader file: folder.getFiles()) {
1262
                        file.setOwner(owner);
1263
                        file.getAuditInfo().setModificationDate(modificationDate);
1264
                        file.getAuditInfo().setModifiedBy(modifier);
1265
                }
1266
                for (Folder sub: folder.getSubfolders())
1267
                        changeOwner(sub, owner, modifier, modificationDate);
1268
                folder.setOwner(owner);
1269
                folder.getAuditInfo().setModificationDate(modificationDate);
1270
                folder.getAuditInfo().setModifiedBy(modifier);
1271
        }
1272

    
1273
        @Override
1274
        public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1275
                // Validate.
1276
                if (userId == null)
1277
                        throw new ObjectNotFoundException("No user specified");
1278

    
1279
                // Do the actual work.
1280
                final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1281
                final List<FileHeader> files = dao.getDeletedFiles(userId);
1282
                for (final FileHeader f : files)
1283
                        result.add(f.getDTO());
1284
                return result;
1285
        }
1286

    
1287
        @Override
1288
        public void removeFileFromTrash(Long userId, Long fileId)
1289
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1290
                if (userId == null)
1291
                        throw new ObjectNotFoundException("No user specified");
1292
                if (fileId == null)
1293
                        throw new ObjectNotFoundException("No file specified");
1294

    
1295
                // Do the actual work.
1296
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1297
                Folder parent = file.getFolder();
1298
                if (parent == null)
1299
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1300
                User user = dao.getEntityById(User.class, userId);
1301
                if (!file.hasDeletePermission(user))
1302
                        throw new InsufficientPermissionsException("User " + user.getUsername() +
1303
                                                " cannot restore file " + file.getName());
1304

    
1305
                file.setDeleted(false);
1306
                dao.update(file);
1307
                touchParentFolders(parent, user, new Date());
1308
        }
1309

    
1310
        @Override
1311
        public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1312
                if (userId == null)
1313
                        throw new ObjectNotFoundException("No user specified");
1314
                if (folderId == null)
1315
                        throw new ObjectNotFoundException("No folder specified");
1316
                Folder folder = dao.getEntityById(Folder.class, folderId);
1317
                User user = dao.getEntityById(User.class, userId);
1318
                if (!folder.hasDeletePermission(user))
1319
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1320
                folder.setDeleted(true);
1321
                dao.update(folder);
1322
                touchParentFolders(folder, user, new Date());
1323
                for (FileHeader file : folder.getFiles())
1324
                        moveFileToTrash(userId, file.getId());
1325
                for (Folder subFolder : folder.getSubfolders())
1326
                        moveFolderToTrash(userId, subFolder.getId());
1327

    
1328
        }
1329

    
1330
        @Override
1331
        public void removeFolderFromTrash(Long userId, Long folderId)
1332
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1333
                if (userId == null)
1334
                        throw new ObjectNotFoundException("No user specified");
1335
                if (folderId == null)
1336
                        throw new ObjectNotFoundException("No folder specified");
1337
                Folder folder = dao.getEntityById(Folder.class, folderId);
1338
                User user = dao.getEntityById(User.class, userId);
1339
                if (!folder.hasDeletePermission(user))
1340
                        throw new InsufficientPermissionsException("User " + user.getUsername() +
1341
                                                " cannot restore folder " + folder.getName());
1342
                folder.setDeleted(false);
1343
                for (FileHeader file : folder.getFiles())
1344
                        removeFileFromTrash(userId, file.getId());
1345
                for (Folder subFolder : folder.getSubfolders())
1346
                        removeFolderFromTrash(userId, subFolder.getId());
1347
                dao.update(folder);
1348
                touchParentFolders(folder, user, new Date());
1349
        }
1350

    
1351
        @Override
1352
        public List<FolderDTO> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1353
                List<Folder> folders = dao.getDeletedRootFolders(userId);
1354
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1355
                for (Folder folder : folders)
1356
                        result.add(folder.getDTO());
1357
                return result;
1358
        }
1359

    
1360
        @Override
1361
        public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1362
                List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1363
                for (FolderDTO fdto : deletedRootFolders)
1364
                        deleteFolder(userId, fdto.getId());
1365
                List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1366
                for (FileHeaderDTO filedto : deletedFiles)
1367
                        deleteFile(userId, filedto.getId());
1368
        }
1369

    
1370
        @Override
1371
        public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1372
                List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1373
                for (FolderDTO fdto : deletedRootFolders)
1374
                        removeFolderFromTrash(userId, fdto.getId());
1375
                List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1376
                for (FileHeaderDTO filedto : deletedFiles)
1377
                        removeFileFromTrash(userId, filedto.getId());
1378
        }
1379

    
1380
        @Override
1381
        public User createUser(String username, String name, String mail,
1382
                                String idp, String idpid) throws ObjectNotFoundException {
1383
                if (username == null)
1384
                        throw new ObjectNotFoundException("No username specified");
1385
                if (name == null)
1386
                        throw new ObjectNotFoundException("No name specified");
1387

    
1388
                User user = new User();
1389
                user.setUsername(username);
1390
                user.setName(name);
1391
                user.setEmail(mail);
1392
                user.setIdentityProvider(idp);
1393
                user.setIdentityProviderId(idpid);
1394
                Date now = new Date();
1395
                AuditInfo auditInfo = new AuditInfo();
1396
                auditInfo.setCreationDate(now);
1397
                auditInfo.setModificationDate(now);
1398
                user.setAuditInfo(auditInfo);
1399
                user.generateAuthToken();
1400
                user.generateWebDAVPassword();
1401
                user.setUserClass(getDefaultUserClass());
1402
                dao.create(user);
1403
                // Make sure we get an ID in the user object.
1404
                dao.flush();
1405
                // Create the root folder for the user.
1406
                createFolder(user.getName(), null, user);
1407
                return user;
1408
        }
1409

    
1410
        /**
1411
         * Get the default user class, which is the one with the lowest quota.
1412
         */
1413
        private UserClass getDefaultUserClass() {
1414
                return getUserClasses().get(0);
1415
        }
1416

    
1417
        @Override
1418
        public List<UserClass> getUserClasses() {
1419
                List<UserClass> classes = dao.getUserClasses();
1420
                // Create a default user class for first-time use. Afterwards, the
1421
                // admin should modify or add to the userclass table.
1422
                if (classes.size() == 0) {
1423
                        UserClass defaultClass = new UserClass();
1424
                        defaultClass.setName("default");
1425
                        Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L));
1426
                        defaultClass.setQuota(defaultQuota);
1427
                        dao.create(defaultClass);
1428
                        classes.add(defaultClass);
1429
                }
1430
                return classes;
1431
        }
1432

    
1433
        @Override
1434
        public User findUserByEmail(String email) {
1435
                return dao.findUserByEmail(email);
1436
        }
1437

    
1438
        @Override
1439
        public void updateUser(User user) {
1440
                dao.update(user);
1441
        }
1442

    
1443
        @Override
1444
        public User findUser(String username) {
1445
                if (username == null)
1446
                        return null;
1447
                return dao.findUser(username);
1448
        }
1449

    
1450
        @Override
1451
        public User updateUserToken(Long userId) throws ObjectNotFoundException {
1452
                if (userId == null)
1453
                        throw new ObjectNotFoundException("No user specified");
1454
                User user = dao.getEntityById(User.class, userId);
1455
                user.generateAuthToken();
1456
                return user;
1457
        }
1458

    
1459
        @Override
1460
        public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1461
                if (userId == null)
1462
                        throw new ObjectNotFoundException("No user specified");
1463
                if (folderId == null)
1464
                        throw new ObjectNotFoundException("No folder specified");
1465
                User user = dao.getEntityById(User.class, userId);
1466
                Folder folder = dao.getEntityById(Folder.class, folderId);
1467
                if(!folder.hasReadPermission(user))
1468
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1469
                Set<Permission> perms = folder.getPermissions();
1470
                Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1471
                for (Permission perm : perms)
1472
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1473
                                result.add(perm.getDTO());
1474
                for (Permission perm : perms)
1475
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1476
                        } else
1477
                                result.add(perm.getDTO());
1478
                return result;
1479

    
1480
        }
1481

    
1482
        /**
1483
         * Set the provided permissions as the new permissions of the specified
1484
         * folder.
1485
         *
1486
         * @param user
1487
         * @param folder
1488
         * @param permissions
1489
         * @throws ObjectNotFoundException
1490
         * @throws InsufficientPermissionsException
1491
         */
1492
        private void setFolderPermissions(User user, Folder folder, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1493
                if (permissions != null && !permissions.isEmpty()) {
1494
                        User owner = folder.getOwner();
1495
                        PermissionDTO ownerPerm = null;
1496
                        for (PermissionDTO dto : permissions)
1497
                                if (dto.getUser() != null && dto.getUser().getId().equals(owner.getId())) {
1498
                                        ownerPerm = dto;
1499
                                        break;
1500
                                }
1501
                        if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1502
                                throw new InsufficientPermissionsException("Can't remove permissions from owner");
1503
                        // Delete previous entries
1504
                        for (Permission perm: folder.getPermissions())
1505
                                dao.delete(perm);
1506
                        folder.getPermissions().clear();
1507
                        for (PermissionDTO dto : permissions) {
1508
                                // Skip 'empty' permission entries.
1509
                                if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1510
                                folder.addPermission(getPermission(dto));
1511
                        }
1512
                        dao.update(folder);
1513
                        for (FileHeader file : folder.getFiles()) {
1514
                                setFilePermissions(file, permissions);
1515
                                Date now = new Date();
1516
                                file.getAuditInfo().setModificationDate(now);
1517
                                file.getAuditInfo().setModifiedBy(user);
1518
                        }
1519
                        for (Folder sub : folder.getSubfolders())
1520
                                setFolderPermissions(user, sub, permissions);
1521
                }
1522
        }
1523

    
1524
        private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1525
                Permission res = new Permission();
1526
                if (dto.getGroup() != null)
1527
                        res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1528
                else if (dto.getUser() != null)
1529
                        if (dto.getUser().getId() == null)
1530
                                res.setUser(dao.getUser(dto.getUser().getUsername()));
1531
                        else
1532
                                res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1533
                res.setRead(dto.hasRead());
1534
                res.setWrite(dto.hasWrite());
1535
                res.setModifyACL(dto.hasModifyACL());
1536
                return res;
1537
        }
1538

    
1539
        /* (non-Javadoc)
1540
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1541
         */
1542
        @Override
1543
        public List<UserDTO> getUsersByUserNameLike(String username) {
1544
                List<User> users = dao.getUsersByUserNameLike(username);
1545
                List<UserDTO> result = new ArrayList<UserDTO>();
1546
                for (User u : users)
1547
                        result.add(u.getDTO());
1548
                return result;
1549

    
1550
        }
1551

    
1552
        @Override
1553
        public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1554
                if (userId == null)
1555
                        throw new ObjectNotFoundException("No user specified");
1556
                if (groupId == null)
1557
                        throw new ObjectNotFoundException("No group specified");
1558
                if (userToAddId == null)
1559
                        throw new ObjectNotFoundException("No user to add specified");
1560
                User user = dao.getEntityById(User.class, userId);
1561
                Group group = dao.getEntityById(Group.class, groupId);
1562
                if (!group.getOwner().equals(user))
1563
                        throw new InsufficientPermissionsException();
1564
                User userToAdd = dao.getEntityById(User.class, userToAddId);
1565
                if (group.contains(userToAdd))
1566
                        throw new DuplicateNameException("User already exists in group");
1567
                group.getMembers().add(userToAdd);
1568
                dao.update(group);
1569

    
1570
        }
1571

    
1572
        @Override
1573
        public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1574
                if (userId == null)
1575
                        throw new ObjectNotFoundException("No user specified");
1576
                User user = dao.getEntityById(User.class, userId);
1577
                user.invalidateAuthToken();
1578
                return;
1579
        }
1580

    
1581
        @Override
1582
        public List<FolderDTO> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1583
                if (userId == null)
1584
                        throw new ObjectNotFoundException("No user specified");
1585
                List<Folder> folders = dao.getSharedRootFolders(userId);
1586
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1587
                for (Folder f : folders) {
1588
                        FolderDTO dto = f.getDTO();
1589
                        dto.setSubfolders(getSharedSubfolders(userId, f.getId()));
1590
                        result.add(dto);
1591
                }
1592
                return result;
1593
        }
1594

    
1595
        @Override
1596
        public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1597
                if (userId == null)
1598
                        throw new ObjectNotFoundException("No user specified");
1599
                if (groupId == null)
1600
                        throw new ObjectNotFoundException("No group specified");
1601
                if (memberId == null)
1602
                        throw new ObjectNotFoundException("No member specified");
1603
                User owner = dao.getEntityById(User.class, userId);
1604
                Group group = dao.getEntityById(Group.class, groupId);
1605
                User member = dao.getEntityById(User.class, memberId);
1606
                if (!group.getOwner().equals(owner))
1607
                        throw new InsufficientPermissionsException("User is not the owner of the group");
1608
                group.removeMemberFromGroup(member);
1609
                dao.update(group);
1610

    
1611
        }
1612

    
1613
        @Override
1614
        public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1615
                List<User> users = dao.getUsersSharingFoldersForUser(userId);
1616
                List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1617
                List<UserDTO> res = new ArrayList<UserDTO>();
1618
                for (User u : users)
1619
                        res.add(u.getDTO());
1620
                for(User fu : usersFiles)
1621
                        if(!users.contains(fu))
1622
                                res.add(fu.getDTO());
1623
                return res;
1624
        }
1625

    
1626
        @Override
1627
        public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1628
                if (userId == null)
1629
                        throw new ObjectNotFoundException("No user specified");
1630
                if (fileId == null)
1631
                        throw new ObjectNotFoundException("No folder specified");
1632
                User user = dao.getEntityById(User.class, userId);
1633
                FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1634
                if(!folder.hasReadPermission(user))
1635
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1636
                Set<Permission> perms = folder.getPermissions();
1637
                Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1638
                for (Permission perm : perms)
1639
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1640
                                result.add(perm.getDTO());
1641
                for (Permission perm : perms)
1642
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1643
                        } else
1644
                                result.add(perm.getDTO());
1645
                return result;
1646
        }
1647

    
1648
        /**
1649
         * Set the provided permissions as the new permissions of the specified
1650
         * file. This method sets the modification date/user attributes to the
1651
         * current values as a side effect.
1652
         *
1653
         * @param file
1654
         * @param permissions
1655
         * @throws ObjectNotFoundException
1656
         * @throws InsufficientPermissionsException
1657
         */
1658
        private void setFilePermissions(FileHeader file,
1659
                                Set<PermissionDTO> permissions)
1660
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1661
                if (permissions != null && !permissions.isEmpty()) {
1662
                        PermissionDTO ownerPerm = null;
1663
                        for (PermissionDTO dto : permissions)
1664
                                if (dto.getUser() != null && dto.getUser().getId().equals(file.getOwner().getId())) {
1665
                                        ownerPerm = dto;
1666
                                        break;
1667
                                }
1668
                        if (ownerPerm == null || !ownerPerm.hasRead() || !ownerPerm.hasWrite() || !ownerPerm.hasModifyACL())
1669
                                throw new InsufficientPermissionsException("Can't remove permissions from owner");
1670
                        // Delete previous entries.
1671
                        for (Permission perm: file.getPermissions())
1672
                                dao.delete(perm);
1673
                        file.getPermissions().clear();
1674
                        for (PermissionDTO dto : permissions) {
1675
                                // Skip 'empty' permission entries.
1676
                                if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1677
                                file.addPermission(getPermission(dto));
1678
                        }
1679
                        dao.flush();
1680
                }
1681
        }
1682

    
1683
        @Override
1684
        public List<FileHeaderDTO> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1685
                if (userId == null)
1686
                        throw new ObjectNotFoundException("No user specified");
1687
                List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1688
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1689
                for (FileHeader f : files)
1690
                        result.add(f.getDTO());
1691
                return result;
1692
        }
1693

    
1694
        @Override
1695
        public List<FileHeaderDTO> getSharedFiles(Long userId) throws ObjectNotFoundException {
1696
                if (userId == null)
1697
                        throw new ObjectNotFoundException("No user specified");
1698
                List<FileHeader> files = dao.getSharedFiles(userId);
1699
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1700
                for (FileHeader f : files)
1701
                        result.add(f.getDTO());
1702
                return result;
1703
        }
1704

    
1705
        @Override
1706
        public List<FolderDTO> getSharedFolders(Long userId) throws ObjectNotFoundException {
1707
                if (userId == null)
1708
                        throw new ObjectNotFoundException("No user specified");
1709
                List<Folder> folders = dao.getSharedFolders(userId);
1710
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1711
                for (Folder f : folders)
1712
                        result.add(f.getDTO());
1713
                return result;
1714
        }
1715

    
1716
        @Override
1717
        public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1718
                if (ownerId == null)
1719
                        throw new ObjectNotFoundException("No owner specified");
1720
                if (callingUserId == null)
1721
                        throw new ObjectNotFoundException("No calling user specified");
1722
                List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1723
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1724
                for (FileHeader f : folders)
1725
                        result.add(f.getDTO());
1726
                return result;
1727
        }
1728

    
1729
        @Override
1730
        public List<FolderDTO> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1731
                if (ownerId == null)
1732
                        throw new ObjectNotFoundException("No owner specified");
1733
                if (callingUserId == null)
1734
                        throw new ObjectNotFoundException("No calling user specified");
1735
                List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1736
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1737
                for (Folder f : folders) {
1738
                        FolderDTO dto = f.getDTO();
1739
                        dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1740
                        result.add(dto);
1741
                }
1742
                return result;
1743

    
1744
        }
1745

    
1746
        @Override
1747
        public List<FolderDTO> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1748
                if (userId == null)
1749
                        throw new ObjectNotFoundException("No user specified");
1750
                if (folderId == null)
1751
                        throw new ObjectNotFoundException("No folder specified");
1752
                User user = dao.getEntityById(User.class, userId);
1753
                Folder folder = dao.getEntityById(Folder.class, folderId);
1754
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1755
                if (folder.isShared(user))
1756
                        for (Folder f : folder.getSubfolders())
1757
                                if (f.isShared(user) && !f.isDeleted())
1758
                                        result.add(f.getDTO());
1759
                return result;
1760
        }
1761

    
1762
        @Override
1763
        public List<FolderDTO> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1764
                if (userId == null)
1765
                        throw new ObjectNotFoundException("No user specified");
1766
                if (callingUserId == null)
1767
                        throw new ObjectNotFoundException("No user specified");
1768
                if (folderId == null)
1769
                        throw new ObjectNotFoundException("No folder specified");
1770
                User user = dao.getEntityById(User.class, callingUserId);
1771
                Folder folder = dao.getEntityById(Folder.class, folderId);
1772
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1773
                if (folder.isSharedForOtherUser(user))
1774
                        for (Folder f : folder.getSubfolders())
1775
                                if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1776
                                        FolderDTO dto = f.getDTO();
1777
                                        dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId()));
1778
                                        result.add(dto);
1779
                                }
1780
                return result;
1781

    
1782
        }
1783

    
1784
        @Override
1785
        public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1786
                if (userId == null)
1787
                        throw new ObjectNotFoundException("No user specified");
1788
                User user = getUser(userId);
1789
                if (query == null)
1790
                        throw new ObjectNotFoundException("No query specified");
1791
                List<FileHeader> files = search(user.getId(), query);
1792
                List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1793
                for(FileHeader f : files)
1794
                        res.add(f.getDTO());
1795
                return res;
1796
        }
1797

    
1798
        /**
1799
         * Performs the actuals search on the solr server and returns the results
1800
         *
1801
         * We have to use the dismax query type (instead of the
1802
         * standard) because it allows for search time field boosting. This is because we can't use indexing
1803
         * time field boosting due to the patched rich indexing API that does not allow it
1804
         *
1805
         * @param userId
1806
         * @param query
1807
         * @return a List of FileHeader objects
1808
         */
1809
        private List<FileHeader> search(Long userId, String query) {
1810
                try {
1811
                        HttpClient httpClient = new HttpClient();
1812

    
1813
                        GetMethod method = new GetMethod(getConfiguration().getString("solrSelectUrl"));
1814
                        NameValuePair[] params = {new NameValuePair("qt", "dismax"),
1815
                                                                                new NameValuePair("q", query),
1816
                                                                                new NameValuePair("sort", "score desc"),
1817
                                                                                new NameValuePair("indent", "on")};
1818
                        method.setQueryString(params);
1819
                        int retryCount = 0;
1820
                        int statusCode = 0;
1821
                        String response = null;
1822
                        do {
1823
                                statusCode = httpClient.executeMethod(method);
1824
                                logger.debug("HTTP status: " + statusCode);
1825
                                response = method.getResponseBodyAsString();
1826
                                logger.debug(response);
1827
                                retryCount++;
1828
                                if (statusCode != 200 && retryCount < 3)
1829
                                        try {
1830
                                                Thread.sleep(3000); //Give Solr a little time to be available
1831
                                        } catch (InterruptedException e) {
1832
                                        }
1833
                        } while (statusCode != 200 && retryCount < 3);
1834
                        if (statusCode != 200)
1835
                                throw new EJBException("Search query return error:\n" + response);
1836

    
1837
                        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1838
                        DocumentBuilder db = dbf.newDocumentBuilder();
1839
                        Document doc = db.parse(method.getResponseBodyAsStream());
1840
                        method.releaseConnection();
1841

    
1842
                        Node root = doc.getElementsByTagName("response").item(0);
1843
                        Node lst = root.getFirstChild().getNextSibling();
1844
                        Node status = lst.getFirstChild().getNextSibling();
1845
                        if (status.getAttributes().getNamedItem("name").getNodeValue().equals("status") &&
1846
                                status.getTextContent().equals("0")) {
1847
                                List<FileHeader> fileResult = new ArrayList<FileHeader>();
1848
                                Node result = lst.getNextSibling().getNextSibling();
1849
                                NodeList docs = result.getChildNodes();
1850
                                User user = getUser(userId);
1851
                                for (int i=1; i<docs.getLength(); i=i+2) {
1852
                                        Node d = docs.item(i);
1853
                                        NodeList docData = d.getChildNodes();
1854
                                        for (int j=1; j<docData.getLength(); j=j+2) {
1855
                                                Node dd = docData.item(j);
1856
                                                if (dd.getAttributes().item(0).getNodeName().equals("name") &&
1857
                                                        dd.getAttributes().item(0).getNodeValue().equals("id")) {
1858
                                                        Long fileId = Long.valueOf(dd.getTextContent());
1859
                                                        try {
1860
                                                                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1861
                                                                if (file.hasReadPermission(user)) {
1862
                                                                        fileResult.add(file);
1863
                                                                        logger.debug("File added " + fileId);
1864
                                                                }
1865
                                                        } catch (ObjectNotFoundException e) {
1866
                                                                logger.warn("Search result not found", e);
1867
                                                        }
1868
                                                }
1869
                                        }
1870
                                }
1871
                                return fileResult;
1872
                        }
1873
                        throw new EJBException();
1874
                } catch (HttpException e) {
1875
                        throw new EJBException(e);
1876
                } catch (IOException e) {
1877
                        throw new EJBException(e);
1878
                } catch (SAXException e) {
1879
                        throw new EJBException(e);
1880
                } catch (ParserConfigurationException e) {
1881
                        throw new EJBException(e);
1882
                } catch (ObjectNotFoundException e) {
1883
                        throw new EJBException(e);
1884
                }
1885
        }
1886

    
1887
        @Override
1888
        public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1889
                for(Long l : fileIds){
1890
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1891
                        copyFile(userId, l, destId, file.getName());
1892
                }
1893

    
1894

    
1895
        }
1896

    
1897
        @Override
1898
        public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1899
                for(Long l : fileIds){
1900
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1901
                        moveFile(userId, l, destId, file.getName());
1902
                }
1903

    
1904
        }
1905

    
1906
        @Override
1907
        public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1908
                if (userId == null)
1909
                        throw new ObjectNotFoundException("No user specified");
1910
                final User user = dao.getEntityById(User.class, userId);
1911
                List<String> filesToRemove = new ArrayList<String>();
1912
                //first delete database objects
1913
                for(Long fileId : fileIds){
1914
                        if (fileId == null)
1915
                                throw new ObjectNotFoundException("No file specified");
1916
                        final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1917
                        final Folder parent = file.getFolder();
1918
                        if (parent == null)
1919
                                throw new ObjectNotFoundException("The specified file has no parent folder");
1920
                        if (!file.hasDeletePermission(user))
1921
                                throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1922

    
1923
                        parent.removeFile(file);
1924
                        for (final FileBody body : file.getBodies())
1925
                                filesToRemove.add(body.getStoredFilePath());
1926
                        dao.delete(file);
1927
                        touchParentFolders(parent, user, new Date());
1928
                }
1929
                //then remove physical files if everything is ok
1930
                for(String physicalFileName : filesToRemove)
1931
                        deleteActualFile(physicalFileName);
1932
                //then unindex deleted files
1933
                for(Long fileId : fileIds)
1934
                        indexFile(fileId, true);
1935

    
1936
        }
1937

    
1938
        @Override
1939
        public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1940
                for(Long l : fileIds)
1941
                        moveFileToTrash(userId, l);
1942

    
1943
        }
1944

    
1945
        @Override
1946
        public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1947
                for(Long l : fileIds)
1948
                        removeFileFromTrash(userId, l);
1949

    
1950
        }
1951

    
1952
        @Override
1953
        public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1954
                if (userId == null)
1955
                        throw new ObjectNotFoundException("No user specified");
1956
                User user = dao.getEntityById(User.class, userId);
1957
                Nonce nonce = Nonce.createNonce(user.getId());
1958
                dao.create(nonce);
1959
                return nonce;
1960
        }
1961

    
1962
        @Override
1963
        public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1964
                if (userId == null)
1965
                        throw new ObjectNotFoundException("No user specified");
1966
                if (nonce == null)
1967
                        throw new ObjectNotFoundException("No nonce specified");
1968
                return dao.getNonce(nonce, userId);
1969
        }
1970

    
1971
        @Override
1972
        public void removeNonce(Long id) throws ObjectNotFoundException {
1973
                if (id == null)
1974
                        throw new ObjectNotFoundException("No nonce specified");
1975
                Nonce nonce = dao.getEntityById(Nonce.class, id);
1976
                dao.delete(nonce);
1977
        }
1978

    
1979
        @Override
1980
        public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1981
                if (userId == null)
1982
                        throw new ObjectNotFoundException("No user specified");
1983
                User user = dao.getEntityById(User.class, userId);
1984
                user.setNonce(nonce);
1985
                user.setNonceExpiryDate(nonceExpiryDate);
1986
        }
1987

    
1988
        @Override
1989
        public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1990
                if (userId == null)
1991
                        throw new ObjectNotFoundException("No user specified");
1992
                StatsDTO stats = new StatsDTO();
1993
                stats.setFileCount(dao.getFileCount(userId));
1994
                Long fileSize = dao.getFileSize(userId);
1995
                stats.setFileSize(fileSize);
1996
                Long quota = getQuota(userId);
1997
                Long quotaLeft = quota - fileSize;
1998
                stats.setQuotaLeftSize(quotaLeft);
1999
                return stats;
2000
        }
2001

    
2002
        @Override
2003
        public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2004
                if (userId == null)
2005
                        throw new ObjectNotFoundException("No user specified");
2006
                if (fileId == null)
2007
                        throw new ObjectNotFoundException("No file specified");
2008
                User user = dao.getEntityById(User.class, userId);
2009
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2010
                if(!header.hasReadPermission(user))
2011
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2012
                List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
2013
                for(int i = header.getBodies().size()-1 ; i>=0; i--)
2014
                        result.add(header.getBodies().get(i).getDTO());
2015
                return result;
2016
        }
2017

    
2018
        @Override
2019
        public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
2020
                if (userId == null)
2021
                        throw new ObjectNotFoundException("No user specified");
2022
                if (fileId == null)
2023
                        throw new ObjectNotFoundException("No file specified");
2024
                if (bodyId == null)
2025
                        throw new ObjectNotFoundException("No body specified");
2026
                User user = dao.getEntityById(User.class, userId);
2027
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2028
                if(!header.hasWritePermission(user))
2029
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2030
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
2031
                if(body.equals(header.getCurrentBody())){
2032

    
2033
                        if(header.getBodies().size() == 1)
2034
                                throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
2035
                        for(FileBody b : header.getBodies())
2036
                                if(b.getVersion() == body.getVersion()-1)
2037
                                        header.setCurrentBody(b);
2038
                }
2039
                deleteActualFile(body.getStoredFilePath());
2040
                header.getBodies().remove(body);
2041

    
2042
                Folder parent = header.getFolder();
2043
                touchParentFolders(parent, user, new Date());
2044

    
2045
        }
2046

    
2047
        @Override
2048
        public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException,  GSSIOException, QuotaExceededException {
2049
                if (userId == null)
2050
                        throw new ObjectNotFoundException("No user specified");
2051
                if (fileId == null)
2052
                        throw new ObjectNotFoundException("No file specified");
2053
                User user = dao.getEntityById(User.class, userId);
2054
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2055
                if(!header.hasWritePermission(user))
2056
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2057
                FileBody body = dao.getFileVersion(fileId, version);
2058
                final File fileContents = new File(body.getStoredFilePath());
2059

    
2060
                try {
2061
                        updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
2062
                } catch (FileNotFoundException e) {
2063
                        throw new GSSIOException(e);
2064
                }
2065

    
2066
        }
2067

    
2068
        /* (non-Javadoc)
2069
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2070
         */
2071
        @Override
2072
        public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2073
                if (userId == null)
2074
                        throw new ObjectNotFoundException("No user specified");
2075
                if (fileId == null)
2076
                        throw new ObjectNotFoundException("No file specified");
2077
                User user = dao.getEntityById(User.class, userId);
2078
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2079
                if(!header.hasWritePermission(user))
2080
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2081
                Iterator<FileBody> it = header.getBodies().iterator();
2082
                while(it.hasNext()){
2083
                        FileBody body = it.next();
2084
                        if(!body.equals(header.getCurrentBody())){
2085
                                deleteActualFile(body.getStoredFilePath());
2086
                                it.remove();
2087
                                dao.delete(body);
2088
                        }
2089
                }
2090
                header.getCurrentBody().setVersion(1);
2091

    
2092
                Folder parent = header.getFolder();
2093
                touchParentFolders(parent, user, new Date());
2094
        }
2095

    
2096
        /**
2097
         * Gets the quota left for specified user ID.
2098
         */
2099
        private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
2100
                Long fileSize = dao.getFileSize(userId);
2101
                Long quota = getQuota(userId);
2102
                return quota - fileSize;
2103
        }
2104

    
2105
        /**
2106
         * Gets the quota for specified user ID.
2107
         */
2108
        private Long getQuota(Long userId) throws ObjectNotFoundException{
2109
                UserClass uc = getUser(userId).getUserClass();
2110
                if (uc == null)
2111
                        uc = getDefaultUserClass();
2112
                return uc.getQuota();
2113
        }
2114

    
2115
        @Override
2116
        public void rebuildSolrIndex() {
2117
                MessageProducer sender = null;
2118
                Session session = null;
2119
                Connection qConn = null;
2120
                try {
2121
                        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2122
                        DocumentBuilder db = dbf.newDocumentBuilder();
2123
                        Document doc = db.newDocument();
2124
                        Node root = doc.createElement("delete");
2125
                        doc.appendChild(root);
2126
                        Node queryNode = doc.createElement("query");
2127
                        root.appendChild(queryNode);
2128
                        queryNode.appendChild(doc.createTextNode("*:*"));
2129

    
2130
                        TransformerFactory fact = TransformerFactory.newInstance();
2131
                        Transformer trans = fact.newTransformer();
2132
                        trans.setOutputProperty(OutputKeys.INDENT, "yes");
2133
                        StringWriter sw = new StringWriter();
2134
                        StreamResult sr = new StreamResult(sw);
2135
                        DOMSource source = new DOMSource(doc);
2136
                        trans.transform(source, sr);
2137
                        logger.debug(sw.toString());
2138

    
2139
                        HttpClient httpClient = new HttpClient();
2140
                        PostMethod method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2141
                        method.setRequestEntity(new StringRequestEntity(sw.toString()));
2142
                        int retryCount = 0;
2143
                        int statusCode = 0;
2144
                        String response = null;
2145
                        do {
2146
                                statusCode = httpClient.executeMethod(method);
2147
                                logger.debug("HTTP status: " + statusCode);
2148
                                response = method.getResponseBodyAsString();
2149
                                logger.debug(response);
2150
                                retryCount++;
2151
                                if (statusCode != 200 && retryCount < 3)
2152
                                        try {
2153
                                                Thread.sleep(10000); //Give Solr a little time to be available
2154
                                        } catch (InterruptedException e) {
2155
                                        }
2156
                        } while (statusCode != 200 && retryCount < 3);
2157
                        method.releaseConnection();
2158
                        if (statusCode != 200)
2159
                                throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response);
2160
                        List<Long> fileIds = dao.getAllFileIds();
2161

    
2162
                        Context jndiCtx = new InitialContext();
2163
                        ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
2164
                        Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
2165
                        qConn = factory.createConnection();
2166
                        session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
2167
                        sender = session.createProducer(queue);
2168

    
2169
                        for (Long id : fileIds) {
2170
                                MapMessage map = session.createMapMessage();
2171
                                map.setObject("id", id);
2172
                                map.setBoolean("delete", false);
2173
                                sender.send(map);
2174
                        }
2175
                        sendOptimize(httpClient, 0);
2176
                } catch (DOMException e) {
2177
                        throw new EJBException(e);
2178
                } catch (TransformerConfigurationException e) {
2179
                        throw new EJBException(e);
2180
                } catch (IllegalArgumentException e) {
2181
                        throw new EJBException(e);
2182
                } catch (HttpException e) {
2183
                        throw new EJBException(e);
2184
                } catch (UnsupportedEncodingException e) {
2185
                        throw new EJBException(e);
2186
                } catch (ParserConfigurationException e) {
2187
                        throw new EJBException(e);
2188
                } catch (TransformerException e) {
2189
                        throw new EJBException(e);
2190
                } catch (IOException e) {
2191
                        throw new EJBException(e);
2192
                } catch (NamingException e) {
2193
                        throw new EJBException(e);
2194
                } catch (JMSException e) {
2195
                        throw new EJBException(e);
2196
                }
2197
                finally {
2198
                        try {
2199
                                if (sender != null)
2200
                                        sender.close();
2201
                                if (session != null)
2202
                                        session.close();
2203
                                if (qConn != null)
2204
                                        qConn.close();
2205
                        }
2206
                        catch (JMSException e) {
2207
                                logger.warn(e);
2208
                        }
2209
                }
2210
        }
2211

    
2212
        /**
2213
         * Sends a optimize message to the solr server
2214
         *
2215
         * @param httpClient
2216
         * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive
2217
         *                                         calls to stop the recursion
2218
         * @throws UnsupportedEncodingException
2219
         * @throws IOException
2220
         * @throws HttpException
2221
         */
2222
        private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException {
2223
                PostMethod method = null;
2224
                try {
2225
                        logger.debug("Optimize retry: " + retryCount);
2226
                        method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2227
                        method.setRequestEntity(new StringRequestEntity("<optimize/>", "text/xml", "iso8859-1"));
2228
                        int statusCode = httpClient.executeMethod(method);
2229
                        logger.debug("HTTP status: " + statusCode);
2230
                        String response = method.getResponseBodyAsString();
2231
                        logger.debug(response);
2232
                        if (statusCode != 200 && retryCount < 2) {
2233
                                try {
2234
                                        Thread.sleep(10000); //Give Solr a little time to be available
2235
                                } catch (InterruptedException e) {
2236
                                }
2237
                                sendOptimize(httpClient, retryCount + 1);
2238
                        }
2239
                }
2240
                finally {
2241
                        if (method != null)
2242
                                method.releaseConnection();
2243
                }
2244
        }
2245

    
2246
        @Override
2247
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2248
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2249
                        InsufficientPermissionsException, QuotaExceededException {
2250
                // Validate.
2251
                if (userId == null)
2252
                        throw new ObjectNotFoundException("No user specified");
2253
                if (folderId == null)
2254
                        throw new ObjectNotFoundException("No folder specified");
2255
                String contentType = mimeType;
2256
                if (StringUtils.isEmpty(mimeType))
2257
                        contentType = DEFAULT_MIME_TYPE;
2258
                if (StringUtils.isEmpty(name))
2259
                        throw new ObjectNotFoundException("No file name specified");
2260
                if (dao.existsFolderOrFile(folderId, name))
2261
                        throw new DuplicateNameException("A folder or file with the name '" + name +
2262
                                                "' already exists at this level");
2263

    
2264
                // Do the actual work.
2265
                Folder parent = null;
2266
                try {
2267
                        parent = dao.getEntityById(Folder.class, folderId);
2268
                } catch (final ObjectNotFoundException onfe) {
2269
                        // Supply a more accurate problem description.
2270
                        throw new ObjectNotFoundException("Parent folder not found");
2271
                }
2272
                final User owner = dao.getEntityById(User.class, userId);
2273
                if (!parent.hasWritePermission(owner))
2274
                        throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2275
                final FileHeader file = new FileHeader();
2276
                file.setName(name);
2277
                parent.addFile(file);
2278
                // set file owner to folder owner
2279
                file.setOwner(parent.getOwner());
2280

    
2281
                final Date now = new Date();
2282
                final AuditInfo auditInfo = new AuditInfo();
2283
                auditInfo.setCreatedBy(owner);
2284
                auditInfo.setCreationDate(now);
2285
                auditInfo.setModifiedBy(owner);
2286
                auditInfo.setModificationDate(now);
2287
                file.setAuditInfo(auditInfo);
2288
                // TODO set the proper versioning flag on creation
2289
                file.setVersioned(false);
2290

    
2291
                for (final Permission p : parent.getPermissions()) {
2292
                        final Permission permission = new Permission();
2293
                        permission.setGroup(p.getGroup());
2294
                        permission.setUser(p.getUser());
2295
                        permission.setRead(p.getRead());
2296
                        permission.setWrite(p.getWrite());
2297
                        permission.setModifyACL(p.getModifyACL());
2298
                        file.addPermission(permission);
2299
                }
2300

    
2301
                // Create the file body.
2302
                try {
2303
                        createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2304
                } catch (FileNotFoundException e) {
2305
                        throw new GSSIOException(e);
2306
                }
2307
                touchParentFolders(parent, owner, new Date());
2308
                dao.flush();
2309
                indexFile(file.getId(), false);
2310

    
2311
                return file.getDTO();
2312
        }
2313

    
2314
        @Override
2315
        public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2316
                if (userId == null)
2317
                        throw new ObjectNotFoundException("No user specified");
2318
                if (fileId == null)
2319
                        throw new ObjectNotFoundException("No file specified");
2320
                String contentType = mimeType;
2321

    
2322
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2323

    
2324
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2325
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2326
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2327
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2328
                        contentType = identifyMimeType(file.getName());
2329

    
2330
                final User owner = dao.getEntityById(User.class, userId);
2331
                if (!file.hasWritePermission(owner))
2332
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2333
                final Date now = new Date();
2334
                final AuditInfo auditInfo = new AuditInfo();
2335
                auditInfo.setCreatedBy(owner);
2336
                auditInfo.setCreationDate(now);
2337
                auditInfo.setModifiedBy(owner);
2338
                auditInfo.setModificationDate(now);
2339
                try {
2340
                        createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2341
                } catch (FileNotFoundException e) {
2342
                        throw new GSSIOException(e);
2343
                }
2344
                Folder parent = file.getFolder();
2345
                touchParentFolders(parent, owner, new Date());
2346

    
2347
                indexFile(fileId, false);
2348
                return file.getDTO();
2349
        }
2350

    
2351
        /**
2352
         * Helper method for identifying mime type by examining the filename extension
2353
         *
2354
         * @param filename
2355
         * @return the mime type
2356
         */
2357
        private String identifyMimeType(String filename) {
2358
                if (filename.indexOf('.') != -1) {
2359
                        String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2360
                        if (".doc".equals(extension))
2361
                                return "application/msword";
2362
                        else if (".xls".equals(extension))
2363
                                return "application/vnd.ms-excel";
2364
                        else if (".ppt".equals(extension))
2365
                                return "application/vnd.ms-powerpoint";
2366
                        else if (".pdf".equals(extension))
2367
                                return "application/pdf";
2368
                        else if (".gif".equals(extension))
2369
                                return "image/gif";
2370
                        else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2371
                                return "image/jpeg";
2372
                        else if (".tiff".equals(extension) || ".tif".equals(extension))
2373
                                return "image/tiff";
2374
                        else if (".png".equals(extension))
2375
                                return "image/png";
2376
                        else if (".bmp".equals(extension))
2377
                                return "image/bmp";
2378
                }
2379
                // when all else fails assign the default mime type
2380
                return DEFAULT_MIME_TYPE;
2381
        }
2382

    
2383
        /**
2384
         * Helper method to create a new file body and attach it as the current body
2385
         * of the provided file header.
2386
         *
2387
         * @param name the original file name
2388
         * @param mimeType the content type
2389
         * @param fileSize the uploaded file size
2390
         * @param filePath the uploaded file full path
2391
         * @param header the file header that will be associated with the new body
2392
         * @param auditInfo the audit info
2393
         * @param owner the owner of the file
2394
         * @throws FileNotFoundException
2395
         * @throws QuotaExceededException
2396
         * @throws ObjectNotFoundException if the owner was not found
2397
         */
2398
        private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2399
                                FileHeader header, AuditInfo auditInfo)
2400
                        throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2401

    
2402
                long currentTotalSize = 0;
2403
                if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2404
                        currentTotalSize = header.getTotalSize();
2405
                Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2406
                if(quotaLeft < fileSize-currentTotalSize) {
2407
                        // quota exceeded -> delete the file
2408
                        deleteActualFile(filePath);
2409
                        throw new QuotaExceededException("Not enough free space available");
2410
                }
2411

    
2412
                FileBody body = new FileBody();
2413

    
2414
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2415
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2416
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2417
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2418
                        body.setMimeType(identifyMimeType(name));
2419
                else
2420
                        body.setMimeType(mimeType);
2421
                body.setAuditInfo(auditInfo);
2422
                body.setFileSize(fileSize);
2423
                body.setOriginalFilename(name);
2424
                body.setStoredFilePath(filePath);
2425
                //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2426
                if(!header.isVersioned() && header.getCurrentBody() != null){
2427
                        header.setCurrentBody(null);
2428
                        if (header.getBodies() != null) {
2429
                                Iterator<FileBody> it = header.getBodies().iterator();
2430
                                while(it.hasNext()){
2431
                                        FileBody bo = it.next();
2432
                                        deleteActualFile(bo.getStoredFilePath());
2433
                                        it.remove();
2434
                                        dao.delete(bo);
2435
                                }
2436
                        }
2437
                }
2438

    
2439
                dao.flush();
2440
                header.addBody(body);
2441
                header.setAuditInfo(auditInfo);
2442

    
2443
                dao.create(body);
2444
        }
2445

    
2446

    
2447
        @Override
2448
        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2449
        public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2450
                if (userId == null)
2451
                        throw new ObjectNotFoundException("No user specified");
2452
                User owner = dao.getEntityById(User.class, userId);
2453
                if(owner == null)
2454
                        throw new ObjectNotFoundException("No user specified");
2455
                long start = 0, end = 0;
2456
                if (logger.isDebugEnabled())
2457
                        start = System.currentTimeMillis();
2458
                File result = new File(generateRepositoryFilePath());
2459
                try {
2460
                        final FileOutputStream output = new FileOutputStream(result);
2461
                        final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2462
                        int n = 0;
2463

    
2464
                        while (-1 != (n = stream.read(buffer)))
2465
                                output.write(buffer, 0, n);
2466
                        output.close();
2467
                        stream.close();
2468
                } catch (IOException e) {
2469
                        if (!result.delete())
2470
                                logger.warn("Could not delete " + result.getPath());
2471
                        throw e;
2472
                }
2473
                if (logger.isDebugEnabled()) {
2474
                        end = System.currentTimeMillis();
2475
                        logger.debug("Time to upload: " + (end - start) + " (msec)");
2476
                }
2477
                return result;
2478
        }
2479

    
2480

    
2481
        @Override
2482
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2483

    
2484
                if (userId == null)
2485
                        throw new ObjectNotFoundException("No user specified");
2486
                User user = dao.getEntityById(User.class, userId);
2487
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2488
                if(status == null){
2489
                        status = new FileUploadStatus();
2490
                        status.setOwner(user);
2491
                        status.setFilename(filename);
2492
                        status.setBytesUploaded(bytesTransfered);
2493
                        status.setFileSize(fileSize);
2494
                        dao.create(status);
2495
                }
2496
                else{
2497
                        status.setBytesUploaded(bytesTransfered);
2498
                        status.setFileSize(fileSize);
2499
                        dao.update(status);
2500
                }
2501

    
2502
        }
2503

    
2504
        @Override
2505
        public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2506
                if (userId == null)
2507
                        throw new ObjectNotFoundException("No user specified");
2508
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2509
                if(status != null)
2510
                        dao.delete(status);
2511
        }
2512

    
2513
        @Override
2514
        public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2515
                return dao.getFileUploadStatus(userId, fileName);
2516
        }
2517

    
2518
        @Override
2519
        public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2520
                if (userId == null)
2521
                        throw new ObjectNotFoundException("No user specified");
2522
                if (folderId == null)
2523
                        throw new ObjectNotFoundException("No folder specified");
2524
                final User user = dao.getEntityById(User.class, userId);
2525
                final Folder folder = dao.getEntityById(Folder.class, folderId);
2526
                // Check permissions
2527
                if (!folder.hasReadPermission(user))
2528
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2529
                List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2530
                if (folder.hasReadPermission(user))
2531
                        for (Folder f : folder.getSubfolders())
2532
                                if (f.hasReadPermission(user) && !f.isDeleted())
2533
                                        subfolders.add(f.getDTO());
2534
                FolderDTO result = folder.getDTO();
2535
                result.setSubfolders(subfolders);
2536
                return folder.getDTO();
2537
        }
2538

    
2539
        @Override
2540
        public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2541
                if (userId == null)
2542
                        throw new ObjectNotFoundException("No user specified");
2543
                if (folderId == null)
2544
                        throw new ObjectNotFoundException("No folder specified");
2545
                User user = dao.getEntityById(User.class, callingUserId);
2546
                Folder folder = dao.getEntityById(Folder.class, folderId);
2547
                // Check permissions
2548
                if (!folder.hasReadPermission(user))
2549
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2550

    
2551
                FolderDTO result = folder.getDTO();
2552
                result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2553
                return result;
2554
        }
2555

    
2556
        @Override
2557
        public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2558
                        throws ObjectNotFoundException, InsufficientPermissionsException {
2559
                if (userId == null)
2560
                        throw new ObjectNotFoundException("No user specified");
2561
                if (fileId == null)
2562
                        throw new ObjectNotFoundException("No file specified");
2563
                if (version < 1)
2564
                        throw new ObjectNotFoundException("No valid version specified");
2565
                User user = dao.getEntityById(User.class, userId);
2566
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2567
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2568
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2569
                FileBody body = dao.getFileVersion(fileId, version);
2570
                return body.getDTO();
2571
        }
2572

    
2573
        @Override
2574
        public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2575
                if (userId == null)
2576
                        throw new ObjectNotFoundException("No user specified");
2577
                User user = dao.getEntityById(User.class, userId);
2578
                user.setAcceptedPolicy(isAccepted);
2579
                return user;
2580
        }
2581

    
2582
        @Override
2583
        public void updateAccounting(User user, Date date, long bandwidthDiff) {
2584
                dao.updateAccounting(user, date, bandwidthDiff);
2585
        }
2586

    
2587
        @Override
2588
        public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2589
                if (userId == null)
2590
                        throw new ObjectNotFoundException("No user specified");
2591
                if (folderId == null)
2592
                        throw new ObjectNotFoundException("No folder specified");
2593
                User user = dao.getEntityById(User.class, userId);
2594
                Folder folder = dao.getEntityById(Folder.class, folderId);
2595
                // Check permissions
2596
                if (!folder.hasReadPermission(user))
2597
                        return false;
2598
                return true;
2599
        }
2600

    
2601
        @Override
2602
        public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2603
                if (userId == null)
2604
                        throw new ObjectNotFoundException("No user specified");
2605
                User user = dao.getEntityById(User.class, userId);
2606
                user.generateWebDAVPassword();
2607
                return user.getWebDAVPassword();
2608
        }
2609

    
2610
        @Override
2611
        public Invitation findInvite(String code) {
2612
                if (code == null)
2613
                        return null;
2614
                return dao.findInvite(code);
2615
        }
2616

    
2617
        @Override
2618
        public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2619
                LDAPConnection lc = new LDAPConnection();
2620
        LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2621
        attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2622
        attributeSet.add(new LDAPAttribute("uid", username));
2623
        attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2624
        attributeSet.add(new LDAPAttribute("sn", lastname));
2625
        attributeSet.add(new LDAPAttribute("givenName", firstname));
2626
        attributeSet.add(new LDAPAttribute("mail", email));
2627
        attributeSet.add(new LDAPAttribute("userPassword", password));
2628
        String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2629
        LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2630
        try {
2631
                lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2632
                lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2633
                                getConfiguration().getString("bindPassword").getBytes("UTF8"));
2634
                lc.add(newEntry);
2635
                logger.info("Successfully added LDAP account: " + dn);
2636
                lc.disconnect();
2637
        } catch(LDAPException e) {
2638
                throw new RuntimeException(e);
2639
        } catch(UnsupportedEncodingException e) {
2640
                throw new RuntimeException(e);
2641
        }
2642

    
2643
        }
2644

    
2645
        @Override
2646
        public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2647
                User user = findUser(username);
2648
                if (user == null)
2649
                        throw new ObjectNotFoundException("The user was not found");
2650
                Invitation invite = findInvite(code);
2651
                if (invite.getUser() != null)
2652
                        throw new InvitationUsedException("This code has already been used");
2653
                invite.setUser(user);
2654
                UserClass couponClass = getCouponUserClass();
2655
                user.setUserClass(couponClass);
2656
                return couponClass;
2657
        }
2658

    
2659
        @Override
2660
        public UserClass getCouponUserClass() {
2661
                return dao.findCouponUserClass();
2662
        }
2663

    
2664
}