Statistics
| Branch: | Tag: | Revision:

root / src / gr / ebs / gss / server / ejb / ExternalAPIBean.java @ 376d0ebf

History | View | Annotate | Download (99.2 kB)

1
/*
2
 * Copyright 2007, 2008, 2009, 2010  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.UnsupportedEncodingException;
55
import java.net.MalformedURLException;
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

    
86
import org.apache.commons.lang.StringUtils;
87
import org.apache.commons.logging.Log;
88
import org.apache.commons.logging.LogFactory;
89
import org.apache.solr.client.solrj.SolrQuery;
90
import org.apache.solr.client.solrj.SolrServerException;
91
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
92
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
93
import org.apache.solr.client.solrj.response.QueryResponse;
94
import org.apache.solr.common.SolrDocument;
95
import org.apache.solr.common.SolrDocumentList;
96
import org.apache.solr.common.SolrException;
97
import org.apache.solr.common.SolrInputDocument;
98
import org.hibernate.exception.ConstraintViolationException;
99

    
100
import com.novell.ldap.LDAPAttribute;
101
import com.novell.ldap.LDAPAttributeSet;
102
import com.novell.ldap.LDAPConnection;
103
import com.novell.ldap.LDAPEntry;
104
import com.novell.ldap.LDAPException;
105

    
106
/**
107
 * The concrete implementation of the ExternalAPI interface.
108
 *
109
 * @author past
110
 */
111
@Stateless
112
public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
113
        /**
114
         * The default MIME type for files without an explicit one.
115
         */
116
        private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
117

    
118
        /**
119
         * The size of the buffer that is used to temporarily store chunks of
120
         * uploaded files, while storing them to the file repository.
121
         */
122
        private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
123

    
124
        /**
125
         * The logger.
126
         */
127
        private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
128

    
129
        /**
130
         * Injected reference to the GSSDAO data access facade.
131
         */
132
        @EJB
133
        private GSSDAO dao;
134

    
135

    
136
        /**
137
         * A cached random number generator for creating unique filenames.
138
         */
139
        private static Random random = new Random();
140

    
141
        /**
142
         * Mark the folder and all of its parent folders as modified from the specified user.
143
         */
144
        private void touchParentFolders(Folder folder, User user, Date date) {
145
                Folder f = folder;
146
                while (f != null) {
147
                        AuditInfo ai = f.getAuditInfo();
148
                        ai.setModifiedBy(user);
149
                        ai.setModificationDate(date);
150
                        f.setAuditInfo(ai);
151
                        f = f.getParent();
152
                }
153
        }
154

    
155
        @Override
156
        public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
157
                if (userId == null)
158
                        throw new ObjectNotFoundException("No user specified");
159
                Folder folder = dao.getRootFolder(userId);
160
                return folder.getDTO();
161
        }
162

    
163
        @Override
164
        public FolderDTO getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
165
                if (userId == null)
166
                        throw new ObjectNotFoundException("No user specified");
167
                if (folderId == null)
168
                        throw new ObjectNotFoundException("No folder specified");
169
                final User user = dao.getEntityById(User.class, userId);
170
                final Folder folder = dao.getEntityById(Folder.class, folderId);
171
                // Check permissions
172
                if (!folder.hasReadPermission(user))
173
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
174
                return folder.getDTO();
175
        }
176

    
177
        @Override
178
        public User getUser(Long userId) throws ObjectNotFoundException {
179
                if (userId == null)
180
                        throw new ObjectNotFoundException("No user specified");
181
                return dao.getEntityById(User.class, userId);
182
        }
183

    
184
        @Override
185
        public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
186
                return getUser(userId).getDTO();
187
        }
188

    
189
        @Override
190
        public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
191
                if (groupId == null)
192
                        throw new ObjectNotFoundException("No group specified");
193
                final Group group = dao.getEntityById(Group.class, groupId);
194
                return group.getDTO();
195
        }
196

    
197
        @Override
198
        public GroupDTO getGroup(Long userId, String name) throws ObjectNotFoundException {
199
                if (userId == null)
200
                        throw new ObjectNotFoundException("No user specified");
201
                if (name == null)
202
                        throw new ObjectNotFoundException("No group specified");
203
                User user = dao.getEntityById(User.class, userId);
204
                List<Group> groups = user.getGroupsSpecified();
205
                for (Group group: groups)
206
                        if (group.getName().equals(name))
207
                                return group.getDTO();
208
                throw new ObjectNotFoundException("Group " + name + " not found");
209
        }
210

    
211
        @Override
212
        public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
213
                if (userId == null)
214
                        throw new ObjectNotFoundException("No user specified");
215
                final List<Group> groups = dao.getGroups(userId);
216
                final List<GroupDTO> result = new ArrayList<GroupDTO>();
217
                for (final Group g : groups)
218
                        result.add(g.getDTO());
219
                return result;
220
        }
221

    
222
        @Override
223
        public List<FileHeaderDTO> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
224
                        throws ObjectNotFoundException, InsufficientPermissionsException {
225
                // Validate.
226
                if (userId == null)
227
                        throw new ObjectNotFoundException("No user specified");
228
                if (folderId == null)
229
                        throw new ObjectNotFoundException("No folder specified");
230
                User user = dao.getEntityById(User.class, userId);
231
                Folder folder = dao.getEntityById(Folder.class, folderId);
232
                if (!folder.hasReadPermission(user))
233
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
234
                // Do the actual work.
235
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
236
                List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
237
                for (FileHeader f : files)
238
                        result.add(f.getDTO());
239
                return result;
240
        }
241

    
242
        @Override
243
        public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
244
                // Validate.
245
                if (userId == null)
246
                        throw new ObjectNotFoundException("No user specified");
247
                if (groupId == null)
248
                        throw new ObjectNotFoundException("No group specified");
249

    
250
                // Do the actual work.
251
                final List<User> users = dao.getUsers(groupId);
252
                final List<UserDTO> result = new ArrayList<UserDTO>();
253
                for (final User u : users)
254
                        result.add(u.getDTO());
255
                return result;
256
        }
257

    
258
        @Override
259
        public FolderDTO createFolder(Long userId, Long parentId, String name)
260
                        throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
261
                // Validate.
262
                if (userId == null)
263
                        throw new ObjectNotFoundException("No user specified");
264
                if (StringUtils.isEmpty(name))
265
                        throw new ObjectNotFoundException("New folder name is empty");
266
                if (parentId == null)
267
                        throw new ObjectNotFoundException("No parent specified");
268
                if (dao.existsFolderOrFile(parentId, name))
269
                        throw new DuplicateNameException("A folder or file with the name '" +
270
                                                name + "' already exists at this level");
271

    
272
                User creator = dao.getEntityById(User.class, userId);
273

    
274
                Folder parent = null;
275
                try {
276
                        parent = dao.getEntityById(Folder.class, parentId);
277
                } catch (ObjectNotFoundException onfe) {
278
                        // Supply a more accurate problem description.
279
                        throw new ObjectNotFoundException("Parent folder not found");
280
                }
281
                if (!parent.hasWritePermission(creator))
282
                        throw new InsufficientPermissionsException("You don't have the permissions" +
283
                                        " to write to this folder");
284

    
285
                // Do the actual work.
286
                return createFolder(name, parent, creator);
287
        }
288

    
289
        /**
290
         * Create a new folder with the provided name, parent and owner.
291
         *
292
         * @param name
293
         * @param parent
294
         * @param creator
295
         * @return the new folder
296
         */
297
        private FolderDTO createFolder(String name, Folder parent, User creator) {
298
                Folder folder = new Folder();
299
                folder.setName(name);
300
                if (parent != null) {
301
                        parent.addSubfolder(folder);
302
                        folder.setOwner(parent.getOwner());
303
                } else
304
                        folder.setOwner(creator);
305

    
306
                Date now = new Date();
307
                AuditInfo auditInfo = new AuditInfo();
308
                auditInfo.setCreatedBy(creator);
309
                auditInfo.setCreationDate(now);
310
                auditInfo.setModifiedBy(creator);
311
                auditInfo.setModificationDate(now);
312
                folder.setAuditInfo(auditInfo);
313
                touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
314

    
315
                if (parent != null)
316
                        for (Permission p : parent.getPermissions()) {
317
                                Permission permission = new Permission();
318
                                permission.setGroup(p.getGroup());
319
                                permission.setUser(p.getUser());
320
                                permission.setRead(p.getRead());
321
                                permission.setWrite(p.getWrite());
322
                                permission.setModifyACL(p.getModifyACL());
323
                                folder.addPermission(permission);
324
                        }
325
                else {
326
                        Permission permission = new Permission();
327
                        permission.setUser(creator);
328
                        permission.setRead(true);
329
                        permission.setWrite(true);
330
                        permission.setModifyACL(true);
331
                        folder.addPermission(permission);
332
                }
333

    
334
                if(parent != null)
335
                        folder.setReadForAll(parent.isReadForAll());
336

    
337
                dao.create(folder);
338
                return folder.getDTO();
339
        }
340

    
341
        @Override
342
        public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
343
                // Validate.
344
                if (userId == null)
345
                        throw new ObjectNotFoundException("No user specified");
346
                if (folderId == null)
347
                        throw new ObjectNotFoundException("No folder specified");
348

    
349
                // Do the actual work.
350
                final Folder folder = dao.getEntityById(Folder.class, folderId);
351
                final Folder parent = folder.getParent();
352
                if (parent == null)
353
                        throw new ObjectNotFoundException("Deleting the root folder is not allowed");
354
                final User user = dao.getEntityById(User.class, userId);
355
                if (!folder.hasDeletePermission(user)) {
356
                        logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
357
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
358
                }
359
                removeSubfolderFiles(folder);
360
                parent.removeSubfolder(folder);
361
                dao.delete(folder);
362
                touchParentFolders(parent, user, new Date());
363
        }
364

    
365
        /**
366
         * Traverses the folder and deletes all actual files (file system)
367
         * regardless of permissions
368
         *
369
         * @param folder
370
         */
371
        private void removeSubfolderFiles(Folder folder) {
372
                //remove files for all subfolders
373
                for (Folder subfolder:folder.getSubfolders())
374
                        removeSubfolderFiles(subfolder);
375
                //remove this folder's file bodies (actual files)
376
                for (FileHeader file:folder.getFiles()) {
377
                        for (FileBody body:file.getBodies())
378
                                deleteActualFile(body.getStoredFilePath());
379
                        indexFile(file.getId(), true);
380
                }
381
        }
382

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

    
403
        @Override
404
        public FolderDTO updateFolder(Long userId, Long folderId, String folderName,
405
                                Boolean readForAll,
406
                                Set<PermissionDTO> permissions)
407
                        throws InsufficientPermissionsException, ObjectNotFoundException,
408
                        DuplicateNameException {
409

    
410
                // Validate.
411
                if (userId == null)
412
                        throw new ObjectNotFoundException("No user specified");
413
                if (folderId == null)
414
                        throw new ObjectNotFoundException("No folder specified");
415

    
416
                Folder folder = dao.getEntityById(Folder.class, folderId);
417
                User user = dao.getEntityById(User.class, userId);
418
                if (folderName != null && !folder.hasWritePermission(user))
419
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
420
                if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
421
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
422
                // Check permissions for making file public.
423
                if (readForAll != null && !user.equals(folder.getOwner()))
424
                                throw new InsufficientPermissionsException("Only the owner can make a folder public or not public");
425

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

    
432
                        // Do the actual modification.
433
                        folder.setName(folderName);
434
                }
435
                if (permissions != null)
436
                        setFolderPermissions(user, folder, permissions);
437
                if (readForAll != null)
438
                        setFolderReadForAll(user, folder, readForAll);
439
                folder.getAuditInfo().setModificationDate(new Date());
440
                folder.getAuditInfo().setModifiedBy(user);
441
                dao.update(folder);
442
                touchParentFolders(folder, user, new Date());
443
                return folder.getDTO();
444
        }
445

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

    
458
                // TODO: Check permissions
459

    
460
                final User owner = dao.getEntityById(User.class, userId);
461

    
462
                // Do the actual work.
463
                owner.createGroup(name);
464
        }
465

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

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

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

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

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

    
556

    
557

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

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

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

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

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

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

    
633
        @Override
634
        public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
635
                return dao.getUserTags(userId);
636
        }
637

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

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

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

    
670
                if (modificationDate != null)
671
                        file.getAuditInfo().setModificationDate(modificationDate);
672
                else
673
                        file.getAuditInfo().setModificationDate(new Date());
674
                file.getAuditInfo().setModifiedBy(user);
675

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

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

    
716
                touchParentFolders(parent, user, new Date());
717

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
974
        }
975

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

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

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

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

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

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

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

    
1063
        }
1064

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1330
        }
1331

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

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

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

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

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

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

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

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

    
1436
        @Override
1437
        public User findUserByEmail(String email) {
1438
                return dao.findUserByEmail(email);
1439
        }
1440

    
1441
        @Override
1442
        public void updateUser(User user) {
1443
                dao.update(user);
1444
        }
1445

    
1446
        @Override
1447
        public User findUser(String username) {
1448
                if (username == null)
1449
                        return null;
1450
                return dao.findUser(username);
1451
        }
1452

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

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

    
1483
        }
1484

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

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

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

    
1553
        }
1554

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

    
1573
        }
1574

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

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

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

    
1614
        }
1615

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

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

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

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

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

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

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

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

    
1747
        }
1748

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

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

    
1785
        }
1786

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

    
1801
        /**
1802
         * Performs the actuals search on the solr server and returns the results
1803
         *
1804
         * @param userId
1805
         * @param query
1806
         * @return a List of FileHeader objects
1807
         */
1808
        private List<FileHeader> search(Long userId, String query) {
1809
                List<FileHeader> result = new ArrayList<FileHeader>();
1810
                try {
1811
                        CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
1812
                        SolrQuery solrQuery = new SolrQuery(escapeCharacters(normalizeSearchQuery(query)));
1813
                        QueryResponse response = solr.query(solrQuery);
1814
                        SolrDocumentList results = response.getResults();
1815
                        User user = getUser(userId);
1816
                        for (SolrDocument d : results) {
1817
                                Long id = Long.valueOf((String) d.getFieldValue("id"));
1818
                                try {
1819
                                        FileHeader f = dao.getEntityById(FileHeader.class, id);
1820
                                        if (f.hasReadPermission(user))
1821
                                                result.add(f);
1822
                                } catch (ObjectNotFoundException e) {
1823
                                        logger.warn("Search result id " + id + " cannot be found", e);
1824
                                }
1825
                        }
1826
                } catch (MalformedURLException e) {
1827
                        logger.error(e);
1828
                        throw new EJBException(e);
1829
                } catch (SolrServerException e) {
1830
                        logger.error(e);
1831
                        throw new EJBException(e);
1832
                } catch (ObjectNotFoundException e) {
1833
                        logger.error(e);
1834
                        throw new EJBException(e);
1835
                }
1836
                return result;
1837
        }
1838

    
1839
        @Override
1840
        public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1841
                for(Long l : fileIds){
1842
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1843
                        copyFile(userId, l, destId, file.getName());
1844
                }
1845

    
1846

    
1847
        }
1848

    
1849
        @Override
1850
        public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1851
                for(Long l : fileIds){
1852
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1853
                        moveFile(userId, l, destId, file.getName());
1854
                }
1855

    
1856
        }
1857

    
1858
        @Override
1859
        public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1860
                if (userId == null)
1861
                        throw new ObjectNotFoundException("No user specified");
1862
                final User user = dao.getEntityById(User.class, userId);
1863
                List<String> filesToRemove = new ArrayList<String>();
1864
                //first delete database objects
1865
                for(Long fileId : fileIds){
1866
                        if (fileId == null)
1867
                                throw new ObjectNotFoundException("No file specified");
1868
                        final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1869
                        final Folder parent = file.getFolder();
1870
                        if (parent == null)
1871
                                throw new ObjectNotFoundException("The specified file has no parent folder");
1872
                        if (!file.hasDeletePermission(user))
1873
                                throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1874

    
1875
                        parent.removeFile(file);
1876
                        for (final FileBody body : file.getBodies())
1877
                                filesToRemove.add(body.getStoredFilePath());
1878
                        dao.delete(file);
1879
                        touchParentFolders(parent, user, new Date());
1880
                }
1881
                //then remove physical files if everything is ok
1882
                for(String physicalFileName : filesToRemove)
1883
                        deleteActualFile(physicalFileName);
1884
                //then unindex deleted files
1885
                for(Long fileId : fileIds)
1886
                        indexFile(fileId, true);
1887

    
1888
        }
1889

    
1890
        @Override
1891
        public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1892
                for(Long l : fileIds)
1893
                        moveFileToTrash(userId, l);
1894

    
1895
        }
1896

    
1897
        @Override
1898
        public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1899
                for(Long l : fileIds)
1900
                        removeFileFromTrash(userId, l);
1901

    
1902
        }
1903

    
1904
        @Override
1905
        public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1906
                if (userId == null)
1907
                        throw new ObjectNotFoundException("No user specified");
1908
                User user = dao.getEntityById(User.class, userId);
1909
                Nonce nonce = Nonce.createNonce(user.getId());
1910
                dao.create(nonce);
1911
                return nonce;
1912
        }
1913

    
1914
        @Override
1915
        public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1916
                if (userId == null)
1917
                        throw new ObjectNotFoundException("No user specified");
1918
                if (nonce == null)
1919
                        throw new ObjectNotFoundException("No nonce specified");
1920
                return dao.getNonce(nonce, userId);
1921
        }
1922

    
1923
        @Override
1924
        public void removeNonce(Long id) throws ObjectNotFoundException {
1925
                if (id == null)
1926
                        throw new ObjectNotFoundException("No nonce specified");
1927
                Nonce nonce = dao.getEntityById(Nonce.class, id);
1928
                dao.delete(nonce);
1929
        }
1930

    
1931
        @Override
1932
        public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1933
                if (userId == null)
1934
                        throw new ObjectNotFoundException("No user specified");
1935
                User user = dao.getEntityById(User.class, userId);
1936
                user.setNonce(nonce);
1937
                user.setNonceExpiryDate(nonceExpiryDate);
1938
        }
1939

    
1940
        @Override
1941
        public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1942
                if (userId == null)
1943
                        throw new ObjectNotFoundException("No user specified");
1944
                StatsDTO stats = new StatsDTO();
1945
                stats.setFileCount(dao.getFileCount(userId));
1946
                Long fileSize = dao.getFileSize(userId);
1947
                stats.setFileSize(fileSize);
1948
                Long quota = getQuota(userId);
1949
                Long quotaLeft = quota - fileSize;
1950
                stats.setQuotaLeftSize(quotaLeft);
1951
                return stats;
1952
        }
1953

    
1954
        @Override
1955
        public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1956
                if (userId == null)
1957
                        throw new ObjectNotFoundException("No user specified");
1958
                if (fileId == null)
1959
                        throw new ObjectNotFoundException("No file specified");
1960
                User user = dao.getEntityById(User.class, userId);
1961
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1962
                if(!header.hasReadPermission(user))
1963
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1964
                List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
1965
                for(int i = header.getBodies().size()-1 ; i>=0; i--)
1966
                        result.add(header.getBodies().get(i).getDTO());
1967
                return result;
1968
        }
1969

    
1970
        @Override
1971
        public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
1972
                if (userId == null)
1973
                        throw new ObjectNotFoundException("No user specified");
1974
                if (fileId == null)
1975
                        throw new ObjectNotFoundException("No file specified");
1976
                if (bodyId == null)
1977
                        throw new ObjectNotFoundException("No body specified");
1978
                User user = dao.getEntityById(User.class, userId);
1979
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1980
                if(!header.hasWritePermission(user))
1981
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1982
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
1983
                if(body.equals(header.getCurrentBody())){
1984

    
1985
                        if(header.getBodies().size() == 1)
1986
                                throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
1987
                        for(FileBody b : header.getBodies())
1988
                                if(b.getVersion() == body.getVersion()-1)
1989
                                        header.setCurrentBody(b);
1990
                }
1991
                deleteActualFile(body.getStoredFilePath());
1992
                header.getBodies().remove(body);
1993

    
1994
                Folder parent = header.getFolder();
1995
                touchParentFolders(parent, user, new Date());
1996

    
1997
        }
1998

    
1999
        @Override
2000
        public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException,  GSSIOException, QuotaExceededException {
2001
                if (userId == null)
2002
                        throw new ObjectNotFoundException("No user specified");
2003
                if (fileId == null)
2004
                        throw new ObjectNotFoundException("No file specified");
2005
                User user = dao.getEntityById(User.class, userId);
2006
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2007
                if(!header.hasWritePermission(user))
2008
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2009
                FileBody body = dao.getFileVersion(fileId, version);
2010
                final File fileContents = new File(body.getStoredFilePath());
2011

    
2012
                try {
2013
                        updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
2014
                } catch (FileNotFoundException e) {
2015
                        throw new GSSIOException(e);
2016
                }
2017

    
2018
        }
2019

    
2020
        /* (non-Javadoc)
2021
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2022
         */
2023
        @Override
2024
        public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2025
                if (userId == null)
2026
                        throw new ObjectNotFoundException("No user specified");
2027
                if (fileId == null)
2028
                        throw new ObjectNotFoundException("No file specified");
2029
                User user = dao.getEntityById(User.class, userId);
2030
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2031
                if(!header.hasWritePermission(user))
2032
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2033
                Iterator<FileBody> it = header.getBodies().iterator();
2034
                while(it.hasNext()){
2035
                        FileBody body = it.next();
2036
                        if(!body.equals(header.getCurrentBody())){
2037
                                deleteActualFile(body.getStoredFilePath());
2038
                                it.remove();
2039
                                dao.delete(body);
2040
                        }
2041
                }
2042
                header.getCurrentBody().setVersion(1);
2043

    
2044
                Folder parent = header.getFolder();
2045
                touchParentFolders(parent, user, new Date());
2046
        }
2047

    
2048
        /**
2049
         * Gets the quota left for specified user ID.
2050
         */
2051
        private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
2052
                Long fileSize = dao.getFileSize(userId);
2053
                Long quota = getQuota(userId);
2054
                return quota - fileSize;
2055
        }
2056

    
2057
        /**
2058
         * Gets the quota for specified user ID.
2059
         */
2060
        private Long getQuota(Long userId) throws ObjectNotFoundException{
2061
                UserClass uc = getUser(userId).getUserClass();
2062
                if (uc == null)
2063
                        uc = getDefaultUserClass();
2064
                return uc.getQuota();
2065
        }
2066

    
2067
        @Override
2068
    @TransactionAttribute(TransactionAttributeType.NEVER)
2069
        public String rebuildSolrIndex() {
2070
                try {
2071
            CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2072
                        solr.deleteByQuery("*:*");
2073
                        solr.commit();
2074
            logger.info("Deleted everything in solr");
2075

    
2076
                        List<Long> fileIds = dao.getAllFileIds();
2077
            logger.info("Total of " + fileIds.size() + " will be indexed");
2078
            int i = 0;
2079
                        for (Long id : fileIds) {
2080
                                postFileToSolr(solr, id);
2081
                i++;
2082
                if (i % 100 == 0) {
2083
                    solr.commit();
2084
                    logger.info("Sent commit to solr at file " + i);
2085
                }
2086
                        }
2087
                        solr.optimize();
2088
                        solr.commit();
2089
            logger.info("Finished indexing of " + i + " files");
2090
            return "Finished indexing of " + i + " files";
2091
                } catch (IOException e) {
2092
                        throw new EJBException(e);
2093
                } catch (SolrServerException e) {
2094
                        throw new EJBException(e);
2095
                }
2096
        }
2097

    
2098
        @Override
2099
    @TransactionAttribute(TransactionAttributeType.NEVER)
2100
        public String refreshSolrIndex() {
2101
                try {
2102
                        CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2103
                        
2104
                        List<Long> fileIds = dao.getAllFileIds();
2105
            logger.info("Total of " + fileIds.size() + " will be indexed");
2106
            int i = 0;
2107
                        for (Long id : fileIds) {
2108
                                postFileToSolr(solr, id);
2109
                i++;
2110
                        }
2111
            if (i % 100 == 0) {
2112
                solr.commit();
2113
                logger.debug("Sent commit to solr at file " + i);
2114
            }
2115
                        solr.optimize();
2116
                        solr.commit();
2117
            logger.info("Finished indexing of " + i + " files");
2118
            return "Finished indexing of " + i + " files";
2119
                } catch (IOException e) {
2120
                        throw new EJBException(e);
2121
                } catch (SolrServerException e) {
2122
                        throw new EJBException(e);
2123
                }
2124
        }
2125

    
2126
        @Override
2127
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2128
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2129
                        InsufficientPermissionsException, QuotaExceededException {
2130
                // Validate.
2131
                if (userId == null)
2132
                        throw new ObjectNotFoundException("No user specified");
2133
                if (folderId == null)
2134
                        throw new ObjectNotFoundException("No folder specified");
2135
                String contentType = mimeType;
2136
                if (StringUtils.isEmpty(mimeType))
2137
                        contentType = DEFAULT_MIME_TYPE;
2138
                if (StringUtils.isEmpty(name))
2139
                        throw new ObjectNotFoundException("No file name specified");
2140
                if (dao.existsFolderOrFile(folderId, name))
2141
                        throw new DuplicateNameException("A folder or file with the name '" + name +
2142
                                                "' already exists at this level");
2143

    
2144
                // Do the actual work.
2145
                Folder parent = null;
2146
                try {
2147
                        parent = dao.getEntityById(Folder.class, folderId);
2148
                } catch (final ObjectNotFoundException onfe) {
2149
                        // Supply a more accurate problem description.
2150
                        throw new ObjectNotFoundException("Parent folder not found");
2151
                }
2152
                final User owner = dao.getEntityById(User.class, userId);
2153
                if (!parent.hasWritePermission(owner))
2154
                        throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2155
                final FileHeader file = new FileHeader();
2156
                file.setName(name);
2157
                parent.addFile(file);
2158
                // set file owner to folder owner
2159
                file.setOwner(parent.getOwner());
2160
                //set file's readForAll value according to parent folder readForAll value
2161
                file.setReadForAll(parent.isReadForAll());
2162

    
2163
                final Date now = new Date();
2164
                final AuditInfo auditInfo = new AuditInfo();
2165
                auditInfo.setCreatedBy(owner);
2166
                auditInfo.setCreationDate(now);
2167
                auditInfo.setModifiedBy(owner);
2168
                auditInfo.setModificationDate(now);
2169
                file.setAuditInfo(auditInfo);
2170
                // TODO set the proper versioning flag on creation
2171
                file.setVersioned(false);
2172

    
2173
                for (final Permission p : parent.getPermissions()) {
2174
                        final Permission permission = new Permission();
2175
                        permission.setGroup(p.getGroup());
2176
                        permission.setUser(p.getUser());
2177
                        permission.setRead(p.getRead());
2178
                        permission.setWrite(p.getWrite());
2179
                        permission.setModifyACL(p.getModifyACL());
2180
                        file.addPermission(permission);
2181
                }
2182

    
2183
                // Create the file body.
2184
                try {
2185
                        createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2186
                } catch (FileNotFoundException e) {
2187
                        throw new GSSIOException(e);
2188
                }
2189
                touchParentFolders(parent, owner, new Date());
2190
                dao.flush();
2191
                indexFile(file.getId(), false);
2192

    
2193
                return file.getDTO();
2194
        }
2195

    
2196
        @Override
2197
        public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2198
                if (userId == null)
2199
                        throw new ObjectNotFoundException("No user specified");
2200
                if (fileId == null)
2201
                        throw new ObjectNotFoundException("No file specified");
2202
                String contentType = mimeType;
2203

    
2204
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2205

    
2206
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2207
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2208
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2209
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2210
                        contentType = identifyMimeType(file.getName());
2211

    
2212
                final User owner = dao.getEntityById(User.class, userId);
2213
                if (!file.hasWritePermission(owner))
2214
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2215
                final Date now = new Date();
2216
                final AuditInfo auditInfo = new AuditInfo();
2217
                auditInfo.setCreatedBy(owner);
2218
                auditInfo.setCreationDate(now);
2219
                auditInfo.setModifiedBy(owner);
2220
                auditInfo.setModificationDate(now);
2221
                try {
2222
                        createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2223
                } catch (FileNotFoundException e) {
2224
                        throw new GSSIOException(e);
2225
                }
2226
                Folder parent = file.getFolder();
2227
                touchParentFolders(parent, owner, new Date());
2228

    
2229
                indexFile(fileId, false);
2230
                return file.getDTO();
2231
        }
2232

    
2233
        /**
2234
         * Helper method for identifying mime type by examining the filename extension
2235
         *
2236
         * @param filename
2237
         * @return the mime type
2238
         */
2239
        private String identifyMimeType(String filename) {
2240
                if (filename.indexOf('.') != -1) {
2241
                        String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2242
                        if (".doc".equals(extension))
2243
                                return "application/msword";
2244
                        else if (".xls".equals(extension))
2245
                                return "application/vnd.ms-excel";
2246
                        else if (".ppt".equals(extension))
2247
                                return "application/vnd.ms-powerpoint";
2248
                        else if (".pdf".equals(extension))
2249
                                return "application/pdf";
2250
                        else if (".gif".equals(extension))
2251
                                return "image/gif";
2252
                        else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2253
                                return "image/jpeg";
2254
                        else if (".tiff".equals(extension) || ".tif".equals(extension))
2255
                                return "image/tiff";
2256
                        else if (".png".equals(extension))
2257
                                return "image/png";
2258
                        else if (".bmp".equals(extension))
2259
                                return "image/bmp";
2260
                }
2261
                // when all else fails assign the default mime type
2262
                return DEFAULT_MIME_TYPE;
2263
        }
2264

    
2265
        /**
2266
         * Helper method to create a new file body and attach it as the current body
2267
         * of the provided file header.
2268
         *
2269
         * @param name the original file name
2270
         * @param mimeType the content type
2271
         * @param fileSize the uploaded file size
2272
         * @param filePath the uploaded file full path
2273
         * @param header the file header that will be associated with the new body
2274
         * @param auditInfo the audit info
2275
         * @throws FileNotFoundException
2276
         * @throws QuotaExceededException
2277
         * @throws ObjectNotFoundException if the owner was not found
2278
         */
2279
        private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2280
                                FileHeader header, AuditInfo auditInfo)
2281
                        throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2282

    
2283
                long currentTotalSize = 0;
2284
                if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2285
                        currentTotalSize = header.getTotalSize();
2286
                Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2287
                if(quotaLeft < fileSize-currentTotalSize) {
2288
                        // quota exceeded -> delete the file
2289
                        deleteActualFile(filePath);
2290
                        throw new QuotaExceededException("Not enough free space available");
2291
                }
2292

    
2293
                FileBody body = new FileBody();
2294

    
2295
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2296
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2297
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2298
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2299
                        body.setMimeType(identifyMimeType(name));
2300
                else
2301
                        body.setMimeType(mimeType);
2302
                body.setAuditInfo(auditInfo);
2303
                body.setFileSize(fileSize);
2304
                body.setOriginalFilename(name);
2305
                body.setStoredFilePath(filePath);
2306
                //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2307
                if(!header.isVersioned() && header.getCurrentBody() != null){
2308
                        header.setCurrentBody(null);
2309
                        if (header.getBodies() != null) {
2310
                                Iterator<FileBody> it = header.getBodies().iterator();
2311
                                while(it.hasNext()){
2312
                                        FileBody bo = it.next();
2313
                                        deleteActualFile(bo.getStoredFilePath());
2314
                                        it.remove();
2315
                                        dao.delete(bo);
2316
                                }
2317
                        }
2318
                }
2319

    
2320
                dao.flush();
2321
                header.addBody(body);
2322
                header.setAuditInfo(auditInfo);
2323

    
2324
                dao.create(body);
2325
        }
2326

    
2327

    
2328
        @Override
2329
        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2330
        public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2331
                if (userId == null)
2332
                        throw new ObjectNotFoundException("No user specified");
2333
                User owner = dao.getEntityById(User.class, userId);
2334
                if(owner == null)
2335
                        throw new ObjectNotFoundException("No user specified");
2336
                long start = 0, end = 0;
2337
                if (logger.isDebugEnabled())
2338
                        start = System.currentTimeMillis();
2339
                File result = new File(generateRepositoryFilePath());
2340
                try {
2341
                        final FileOutputStream output = new FileOutputStream(result);
2342
                        final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2343
                        int n = 0;
2344

    
2345
                        while (-1 != (n = stream.read(buffer)))
2346
                                output.write(buffer, 0, n);
2347
                        output.close();
2348
                        stream.close();
2349
                } catch (IOException e) {
2350
                        if (!result.delete())
2351
                                logger.warn("Could not delete " + result.getPath());
2352
                        throw e;
2353
                }
2354
                if (logger.isDebugEnabled()) {
2355
                        end = System.currentTimeMillis();
2356
                        logger.debug("Time to upload: " + (end - start) + " (msec)");
2357
                }
2358
                return result;
2359
        }
2360

    
2361

    
2362
        @Override
2363
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2364

    
2365
                if (userId == null)
2366
                        throw new ObjectNotFoundException("No user specified");
2367
                User user = dao.getEntityById(User.class, userId);
2368
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2369
                if(status == null){
2370
                        status = new FileUploadStatus();
2371
                        status.setOwner(user);
2372
                        status.setFilename(filename);
2373
                        status.setBytesUploaded(bytesTransfered);
2374
                        status.setFileSize(fileSize);
2375
                        dao.create(status);
2376
                }
2377
                else{
2378
                        status.setBytesUploaded(bytesTransfered);
2379
                        status.setFileSize(fileSize);
2380
                        dao.update(status);
2381
                }
2382

    
2383
        }
2384

    
2385
        @Override
2386
        public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2387
                if (userId == null)
2388
                        throw new ObjectNotFoundException("No user specified");
2389
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2390
                if(status != null)
2391
                        dao.delete(status);
2392
        }
2393

    
2394
        @Override
2395
        public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2396
                return dao.getFileUploadStatus(userId, fileName);
2397
        }
2398

    
2399
        @Override
2400
        public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2401
                if (userId == null)
2402
                        throw new ObjectNotFoundException("No user specified");
2403
                if (folderId == null)
2404
                        throw new ObjectNotFoundException("No folder specified");
2405
                final User user = dao.getEntityById(User.class, userId);
2406
                final Folder folder = dao.getEntityById(Folder.class, folderId);
2407
                // Check permissions
2408
                if (!folder.hasReadPermission(user))
2409
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2410
                List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2411
                if (folder.hasReadPermission(user))
2412
                        for (Folder f : folder.getSubfolders())
2413
                                if (f.hasReadPermission(user) && !f.isDeleted())
2414
                                        subfolders.add(f.getDTO());
2415
                FolderDTO result = folder.getDTO();
2416
                result.setSubfolders(subfolders);
2417
                return folder.getDTO();
2418
        }
2419

    
2420
        @Override
2421
        public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2422
                if (userId == null)
2423
                        throw new ObjectNotFoundException("No user specified");
2424
                if (folderId == null)
2425
                        throw new ObjectNotFoundException("No folder specified");
2426
                User user = dao.getEntityById(User.class, callingUserId);
2427
                Folder folder = dao.getEntityById(Folder.class, folderId);
2428
                // Check permissions
2429
                if (!folder.hasReadPermission(user))
2430
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2431

    
2432
                FolderDTO result = folder.getDTO();
2433
                result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2434
                return result;
2435
        }
2436

    
2437
        @Override
2438
        public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2439
                        throws ObjectNotFoundException, InsufficientPermissionsException {
2440
                if (userId == null)
2441
                        throw new ObjectNotFoundException("No user specified");
2442
                if (fileId == null)
2443
                        throw new ObjectNotFoundException("No file specified");
2444
                if (version < 1)
2445
                        throw new ObjectNotFoundException("No valid version specified");
2446
                User user = dao.getEntityById(User.class, userId);
2447
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2448
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2449
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2450
                FileBody body = dao.getFileVersion(fileId, version);
2451
                return body.getDTO();
2452
        }
2453

    
2454
        @Override
2455
        public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2456
                if (userId == null)
2457
                        throw new ObjectNotFoundException("No user specified");
2458
                User user = dao.getEntityById(User.class, userId);
2459
                user.setAcceptedPolicy(isAccepted);
2460
                return user;
2461
        }
2462

    
2463
        @Override
2464
        public void updateAccounting(User user, Date date, long bandwidthDiff) {
2465
                dao.updateAccounting(user, date, bandwidthDiff);
2466
        }
2467

    
2468
        @Override
2469
        public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2470
                if (userId == null)
2471
                        throw new ObjectNotFoundException("No user specified");
2472
                if (folderId == null)
2473
                        throw new ObjectNotFoundException("No folder specified");
2474
                User user = dao.getEntityById(User.class, userId);
2475
                Folder folder = dao.getEntityById(Folder.class, folderId);
2476
                // Check permissions
2477
                if (!folder.hasReadPermission(user))
2478
                        return false;
2479
                return true;
2480
        }
2481

    
2482
        @Override
2483
        public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2484
                if (userId == null)
2485
                        throw new ObjectNotFoundException("No user specified");
2486
                User user = dao.getEntityById(User.class, userId);
2487
                user.generateWebDAVPassword();
2488
                return user.getWebDAVPassword();
2489
        }
2490

    
2491
        @Override
2492
        public Invitation findInvite(String code) {
2493
                if (code == null)
2494
                        return null;
2495
                return dao.findInvite(code);
2496
        }
2497

    
2498
        @Override
2499
        public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2500
                LDAPConnection lc = new LDAPConnection();
2501
        LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2502
        attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2503
        attributeSet.add(new LDAPAttribute("uid", username));
2504
        attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2505
        attributeSet.add(new LDAPAttribute("sn", lastname));
2506
        attributeSet.add(new LDAPAttribute("givenName", firstname));
2507
        attributeSet.add(new LDAPAttribute("mail", email));
2508
        attributeSet.add(new LDAPAttribute("userPassword", password));
2509
        String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2510
        LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2511
        try {
2512
                lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2513
                lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2514
                                getConfiguration().getString("bindPassword").getBytes("UTF8"));
2515
                lc.add(newEntry);
2516
                logger.info("Successfully added LDAP account: " + dn);
2517
                lc.disconnect();
2518
        } catch(LDAPException e) {
2519
                throw new RuntimeException(e);
2520
        } catch(UnsupportedEncodingException e) {
2521
                throw new RuntimeException(e);
2522
        }
2523

    
2524
        }
2525

    
2526
        @Override
2527
        public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2528
                User user = findUser(username);
2529
                if (user == null)
2530
                        throw new ObjectNotFoundException("The user was not found");
2531
                Invitation invite = findInvite(code);
2532
                if (invite.getUser() != null)
2533
                        throw new InvitationUsedException("This code has already been used");
2534
                invite.setUser(user);
2535
                UserClass couponClass = getCouponUserClass();
2536
                user.setUserClass(couponClass);
2537
                return couponClass;
2538
        }
2539

    
2540
        @Override
2541
        public UserClass getCouponUserClass() {
2542
                return dao.findCouponUserClass();
2543
        }
2544

    
2545
        /**
2546
         * Mark the folder as modified from the specified user and change it's modification date.
2547
         */
2548
        private void touchFolder(Folder f, User _user, Date now){
2549
                final AuditInfo auditInfo = f.getAuditInfo();
2550
                auditInfo.setModificationDate(now);
2551
                auditInfo.setModifiedBy(_user);
2552
                f.setAuditInfo(auditInfo);
2553
        }
2554

    
2555
        /**
2556
         * Mark the file as modified from the specified user and change it's modification date.
2557
         */
2558
        private void touchFile(FileHeader f, User _user, Date now){
2559
                final AuditInfo auditInfo = f.getAuditInfo();
2560
                auditInfo.setModificationDate(now);
2561
                auditInfo.setModifiedBy(_user);
2562
                f.setAuditInfo(auditInfo);
2563
        }
2564

    
2565
        /**
2566
         * Set the provided readForAll as the new readforAll value of the specified
2567
         * folder and sub-folders.
2568
         *
2569
         * @param user
2570
         * @param folder
2571
         * @param readForAll
2572
         * @throws ObjectNotFoundException
2573
         *
2574
         */
2575
        private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){
2576
                if (readForAll != null && user.equals(folder.getOwner())){
2577
                        folder.setReadForAll(readForAll);
2578
                        dao.update(folder);
2579
                        for (FileHeader file : folder.getFiles())
2580
                                file.setReadForAll(readForAll);
2581
                        if(readForAll)
2582
                                //only update subfolders when readforall is true. otherwise all sub-folders stay untouched
2583
                                for (Folder sub : folder.getSubfolders())
2584
                                        setFolderReadForAll(user, sub, readForAll);
2585

    
2586
                }
2587

    
2588
        }
2589

    
2590
        @Override
2591
        public void postFileToSolr(CommonsHttpSolrServer solr, Long id) {
2592
                try {
2593
                        FileHeader file = dao.getFileForIndexing(id);
2594
                        FileBody body = file.getCurrentBody();
2595
                        String mime = body.getMimeType();
2596
                        boolean multipart = true;
2597
                        if (!mime.equals("application/pdf") 
2598
                                                && !mime.equals("text/plain")
2599
                                                && !mime.equals("text/html")
2600
                                                && !mime.endsWith("msword")
2601
                                                && !mime.endsWith("ms-excel")
2602
                                                && !mime.endsWith("powerpoint")
2603
                                                || (body.getFileSize() > getConfiguration().getLong("solrDocumentUploadLimitInKB") * 1024))
2604
                                multipart = false;
2605

    
2606
                        if (!multipart)
2607
                                sendMetaDataOnly(solr, file);
2608
                        else {
2609
                ContentStreamUpdateRequest solrRequest = new ContentStreamUpdateRequest(getConfiguration().getString("solr.rich.update.path"));
2610
                                solrRequest.setParam("literal.id", file.getId().toString());
2611
                                solrRequest.setParam("literal.name", file.getName());
2612
                                for (FileTag t : file.getFileTags()) {
2613
                                        solrRequest.getParams().add("literal.tag", t.getTag());
2614
                                }
2615
                File fsFile = new File(body.getStoredFilePath());
2616
                                solrRequest.addFile(fsFile);
2617
//                                solrRequest.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
2618
                                try {
2619
                                        solr.request(solrRequest);
2620
                                }
2621
                                catch (SolrException e) {
2622
                                        logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2623
                                        //Let 's try without the file
2624
                                        sendMetaDataOnly(solr, file);
2625
                                }
2626
                                catch (NullPointerException e) {
2627
                                        logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2628
                                        //Let 's try without the file
2629
                                        sendMetaDataOnly(solr, file);
2630
                                }
2631
                                catch (SolrServerException e) {
2632
                                        logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2633
                                        //Let 's try without the file
2634
                                        sendMetaDataOnly(solr, file);
2635
                                }
2636
                        }
2637
                } catch (MalformedURLException e) {
2638
                        throw new EJBException(e);
2639
                } catch (ObjectNotFoundException e) {
2640
                        logger.error("Indexing of file id " + id + " failed.", e);
2641
                } catch (SolrServerException e) {
2642
                        throw new EJBException(e);
2643
                } catch (IOException e) {
2644
                        throw new EJBException(e);
2645
                }
2646
        }
2647

    
2648
        private void sendMetaDataOnly(CommonsHttpSolrServer solr, FileHeader file) throws SolrServerException, IOException {
2649
                SolrInputDocument solrDoc = new SolrInputDocument();
2650
                solrDoc.addField("id", file.getId().toString());
2651
                solrDoc.addField("name", file.getName());
2652
                for (FileTag t : file.getFileTags()) {
2653
                        solrDoc.addField("tag", t.getTag());
2654
                }
2655
                solr.add(solrDoc);
2656
        }
2657

    
2658
        private String tokenizeFilename(String filename){
2659
                StringBuffer result = new StringBuffer();
2660
                StringTokenizer tokenizer = new StringTokenizer(filename,"._");
2661
                while(tokenizer.hasMoreTokens()){
2662
                        result.append(tokenizer.nextToken());
2663
                        result.append(" ");
2664
                }
2665
                result.append(filename);
2666
                return result.toString();
2667
        }
2668

    
2669
        private String normalizeSearchQuery(String query) {
2670
                if (query.contains("*"))
2671
                        return query.toLowerCase().replace('ά', 'α').replace('έ', 'ε').replace('ί', 'ι').replace('ή', 'η').replace('ύ', 'υ')
2672
                                        .replace('ό', 'ο').replace('ς', 'σ').replace('ώ', 'ω').replace('ϊ', 'ι').replace('ϋ', 'υ');
2673
                else
2674
                        return query;
2675
        }
2676
        
2677
        private String escapeCharacters(String text) {
2678
                return text.replaceAll(":", "\\\\:");
2679
        }
2680
}