Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (101.4 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.UserLogin;
41
import gr.ebs.gss.server.domain.dto.FileBodyDTO;
42
import gr.ebs.gss.server.domain.dto.FileHeaderDTO;
43
import gr.ebs.gss.server.domain.dto.FolderDTO;
44
import gr.ebs.gss.server.domain.dto.GroupDTO;
45
import gr.ebs.gss.server.domain.dto.PermissionDTO;
46
import gr.ebs.gss.server.domain.dto.StatsDTO;
47
import gr.ebs.gss.server.domain.dto.UserDTO;
48

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

    
68
import javax.ejb.EJB;
69
import javax.ejb.EJBException;
70
import javax.ejb.EJBTransactionRolledbackException;
71
import javax.ejb.Stateless;
72
import javax.ejb.TransactionAttribute;
73
import javax.ejb.TransactionAttributeType;
74
import javax.jms.Connection;
75
import javax.jms.ConnectionFactory;
76
import javax.jms.JMSException;
77
import javax.jms.MapMessage;
78
import javax.jms.MessageProducer;
79
import javax.jms.Queue;
80
import javax.jms.QueueConnectionFactory;
81
import javax.jms.Session;
82
import javax.naming.Context;
83
import javax.naming.InitialContext;
84
import javax.naming.NamingException;
85
import javax.persistence.PersistenceException;
86

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

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

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

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

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

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

    
136

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
459
                // TODO: Check permissions
460

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

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

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

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

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

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

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

    
557

    
558

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
975
        }
976

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

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

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

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

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

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

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

    
1064
        }
1065

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1331
        }
1332

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1484
        }
1485

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

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

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

    
1554
        }
1555

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

    
1574
        }
1575

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

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

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

    
1615
        }
1616

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

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

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

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

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

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

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

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

    
1748
        }
1749

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

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

    
1786
        }
1787

    
1788
        @Override
1789
        public List<FileHeader> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1790
        long startTime = System.currentTimeMillis();
1791
                if (userId == null)
1792
                        throw new ObjectNotFoundException("No user specified");
1793
                User user = getUser(userId);
1794
                if (query == null)
1795
                        throw new ObjectNotFoundException("No query specified");
1796
                List<FileHeader> files = search(user.getId(), query);
1797
                
1798
        long stopTime = System.currentTimeMillis();
1799
        logger.info("Total time: " + (stopTime - startTime));
1800
                return files;
1801
        }
1802

    
1803
        /**
1804
         * Performs the actuals search on the solr server and returns the results
1805
         *
1806
         * @param userId
1807
         * @param query
1808
         * @return a List of FileHeader objects
1809
         */
1810
        private List<FileHeader> search(Long userId, String query) {
1811
        final int maxRows = 100;
1812
                List<FileHeader> result = new ArrayList<FileHeader>();
1813
                try {
1814
                        CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
1815
                        SolrQuery solrQuery = new SolrQuery(escapeCharacters(normalizeSearchQuery(query)));
1816
            solrQuery.setRows(maxRows);
1817
            long startTime = System.currentTimeMillis();
1818
                        QueryResponse response = solr.query(solrQuery);
1819
                        SolrDocumentList results = response.getResults();
1820
            if (results.getNumFound() > maxRows) {
1821
                solrQuery.setRows(Integer.valueOf((int) results.getNumFound()));
1822
                response = solr.query(solrQuery);
1823
                results = response.getResults();
1824
            }
1825
            long stopTime = System.currentTimeMillis();
1826
            logger.info("Search time:" +  (stopTime - startTime));
1827
                        User user = getUser(userId);
1828
            startTime = System.currentTimeMillis();
1829
                        for (SolrDocument d : results) {
1830
                                Long id = Long.valueOf((String) d.getFieldValue("id"));
1831
                                try {
1832
                                        FileHeader f = dao.getEntityById(FileHeader.class, id);
1833
                                        if (f.hasReadPermission(user))
1834
                                                result.add(f);
1835
                                } catch (ObjectNotFoundException e) {
1836
                                        logger.warn("Search result id " + id + " cannot be found", e);
1837
                                }
1838
                        }
1839
            stopTime = System.currentTimeMillis();
1840
            logger.info("Permission checks: " + (stopTime - startTime));
1841
                } catch (MalformedURLException e) {
1842
                        logger.error(e);
1843
                        throw new EJBException(e);
1844
                } catch (SolrServerException e) {
1845
                        logger.error(e);
1846
                        throw new EJBException(e);
1847
                } catch (ObjectNotFoundException e) {
1848
                        logger.error(e);
1849
                        throw new EJBException(e);
1850
                }
1851
                return result;
1852
        }
1853

    
1854
        @Override
1855
        public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1856
                for(Long l : fileIds){
1857
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1858
                        copyFile(userId, l, destId, file.getName());
1859
                }
1860

    
1861

    
1862
        }
1863

    
1864
        @Override
1865
        public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1866
                for(Long l : fileIds){
1867
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1868
                        moveFile(userId, l, destId, file.getName());
1869
                }
1870

    
1871
        }
1872

    
1873
        @Override
1874
        public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1875
                if (userId == null)
1876
                        throw new ObjectNotFoundException("No user specified");
1877
                final User user = dao.getEntityById(User.class, userId);
1878
                List<String> filesToRemove = new ArrayList<String>();
1879
                //first delete database objects
1880
                for(Long fileId : fileIds){
1881
                        if (fileId == null)
1882
                                throw new ObjectNotFoundException("No file specified");
1883
                        final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1884
                        final Folder parent = file.getFolder();
1885
                        if (parent == null)
1886
                                throw new ObjectNotFoundException("The specified file has no parent folder");
1887
                        if (!file.hasDeletePermission(user))
1888
                                throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1889

    
1890
                        parent.removeFile(file);
1891
                        for (final FileBody body : file.getBodies())
1892
                                filesToRemove.add(body.getStoredFilePath());
1893
                        dao.delete(file);
1894
                        touchParentFolders(parent, user, new Date());
1895
                }
1896
                //then remove physical files if everything is ok
1897
                for(String physicalFileName : filesToRemove)
1898
                        deleteActualFile(physicalFileName);
1899
                //then unindex deleted files
1900
                for(Long fileId : fileIds)
1901
                        indexFile(fileId, true);
1902

    
1903
        }
1904

    
1905
        @Override
1906
        public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1907
                for(Long l : fileIds)
1908
                        moveFileToTrash(userId, l);
1909

    
1910
        }
1911

    
1912
        @Override
1913
        public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1914
                for(Long l : fileIds)
1915
                        removeFileFromTrash(userId, l);
1916

    
1917
        }
1918

    
1919
        @Override
1920
        public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1921
                if (userId == null)
1922
                        throw new ObjectNotFoundException("No user specified");
1923
                User user = dao.getEntityById(User.class, userId);
1924
                Nonce nonce = Nonce.createNonce(user.getId());
1925
                dao.create(nonce);
1926
                return nonce;
1927
        }
1928

    
1929
        @Override
1930
        public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1931
                if (userId == null)
1932
                        throw new ObjectNotFoundException("No user specified");
1933
                if (nonce == null)
1934
                        throw new ObjectNotFoundException("No nonce specified");
1935
                return dao.getNonce(nonce, userId);
1936
        }
1937

    
1938
        @Override
1939
        public void removeNonce(Long id) throws ObjectNotFoundException {
1940
                if (id == null)
1941
                        throw new ObjectNotFoundException("No nonce specified");
1942
                Nonce nonce = dao.getEntityById(Nonce.class, id);
1943
                dao.delete(nonce);
1944
        }
1945

    
1946
        @Override
1947
        public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1948
                if (userId == null)
1949
                        throw new ObjectNotFoundException("No user specified");
1950
                User user = dao.getEntityById(User.class, userId);
1951
                user.setNonce(nonce);
1952
                user.setNonceExpiryDate(nonceExpiryDate);
1953
        }
1954

    
1955
        @Override
1956
        public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1957
                if (userId == null)
1958
                        throw new ObjectNotFoundException("No user specified");
1959
                StatsDTO stats = new StatsDTO();
1960
                stats.setFileCount(dao.getFileCount(userId));
1961
                Long fileSize = dao.getFileSize(userId);
1962
                stats.setFileSize(fileSize);
1963
                Long quota = getQuota(userId);
1964
                Long quotaLeft = quota - fileSize;
1965
                stats.setQuotaLeftSize(quotaLeft);
1966
                return stats;
1967
        }
1968

    
1969
        @Override
1970
        public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1971
                if (userId == null)
1972
                        throw new ObjectNotFoundException("No user specified");
1973
                if (fileId == null)
1974
                        throw new ObjectNotFoundException("No file specified");
1975
                User user = dao.getEntityById(User.class, userId);
1976
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1977
                if(!header.hasReadPermission(user))
1978
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1979
                List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
1980
                for(int i = header.getBodies().size()-1 ; i>=0; i--)
1981
                        result.add(header.getBodies().get(i).getDTO());
1982
                return result;
1983
        }
1984

    
1985
        @Override
1986
        public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
1987
                if (userId == null)
1988
                        throw new ObjectNotFoundException("No user specified");
1989
                if (fileId == null)
1990
                        throw new ObjectNotFoundException("No file specified");
1991
                if (bodyId == null)
1992
                        throw new ObjectNotFoundException("No body specified");
1993
                User user = dao.getEntityById(User.class, userId);
1994
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1995
                if(!header.hasWritePermission(user))
1996
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1997
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
1998
                if(body.equals(header.getCurrentBody())){
1999

    
2000
                        if(header.getBodies().size() == 1)
2001
                                throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
2002
                        for(FileBody b : header.getBodies())
2003
                                if(b.getVersion() == body.getVersion()-1)
2004
                                        header.setCurrentBody(b);
2005
                }
2006
                deleteActualFile(body.getStoredFilePath());
2007
                header.getBodies().remove(body);
2008

    
2009
                Folder parent = header.getFolder();
2010
                touchParentFolders(parent, user, new Date());
2011

    
2012
        }
2013

    
2014
        @Override
2015
        public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException,  GSSIOException, QuotaExceededException {
2016
                if (userId == null)
2017
                        throw new ObjectNotFoundException("No user specified");
2018
                if (fileId == null)
2019
                        throw new ObjectNotFoundException("No file specified");
2020
                User user = dao.getEntityById(User.class, userId);
2021
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2022
                if(!header.hasWritePermission(user))
2023
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2024
                FileBody body = dao.getFileVersion(fileId, version);
2025
                final File fileContents = new File(body.getStoredFilePath());
2026

    
2027
                try {
2028
                        updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
2029
                } catch (FileNotFoundException e) {
2030
                        throw new GSSIOException(e);
2031
                }
2032

    
2033
        }
2034

    
2035
        /* (non-Javadoc)
2036
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2037
         */
2038
        @Override
2039
        public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2040
                if (userId == null)
2041
                        throw new ObjectNotFoundException("No user specified");
2042
                if (fileId == null)
2043
                        throw new ObjectNotFoundException("No file specified");
2044
                User user = dao.getEntityById(User.class, userId);
2045
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2046
                if(!header.hasWritePermission(user))
2047
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2048
                Iterator<FileBody> it = header.getBodies().iterator();
2049
                while(it.hasNext()){
2050
                        FileBody body = it.next();
2051
                        if(!body.equals(header.getCurrentBody())){
2052
                                deleteActualFile(body.getStoredFilePath());
2053
                                it.remove();
2054
                                dao.delete(body);
2055
                        }
2056
                }
2057
                header.getCurrentBody().setVersion(1);
2058

    
2059
                Folder parent = header.getFolder();
2060
                touchParentFolders(parent, user, new Date());
2061
        }
2062

    
2063
        /**
2064
         * Gets the quota left for specified user ID.
2065
         */
2066
        private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
2067
                Long fileSize = dao.getFileSize(userId);
2068
                Long quota = getQuota(userId);
2069
                return quota - fileSize;
2070
        }
2071

    
2072
        /**
2073
         * Gets the quota for specified user ID.
2074
         */
2075
        private Long getQuota(Long userId) throws ObjectNotFoundException{
2076
                UserClass uc = getUser(userId).getUserClass();
2077
                if (uc == null)
2078
                        uc = getDefaultUserClass();
2079
                return uc.getQuota();
2080
        }
2081

    
2082
        @Override
2083
    @TransactionAttribute(TransactionAttributeType.NEVER)
2084
        public String rebuildSolrIndex() {
2085
                try {
2086
            CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2087
                        solr.deleteByQuery("*:*");
2088
                        solr.commit();
2089
            logger.info("Deleted everything in solr");
2090

    
2091
                        List<Long> fileIds = dao.getAllFileIds();
2092
            logger.info("Total of " + fileIds.size() + " will be indexed");
2093
            int i = 0;
2094
                        for (Long id : fileIds) {
2095
                                postFileToSolr(solr, id);
2096
                i++;
2097
                if (i % 100 == 0) {
2098
                    solr.commit();
2099
                    logger.info("Sent commit to solr at file " + i);
2100
                }
2101
                        }
2102
                        solr.optimize();
2103
                        solr.commit();
2104
            logger.info("Finished indexing of " + i + " files");
2105
            return "Finished indexing of " + i + " files";
2106
                } catch (IOException e) {
2107
                        throw new EJBException(e);
2108
                } catch (SolrServerException e) {
2109
                        throw new EJBException(e);
2110
                }
2111
        }
2112

    
2113
        @Override
2114
    @TransactionAttribute(TransactionAttributeType.NEVER)
2115
        public String refreshSolrIndex() {
2116
                try {
2117
                        CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2118
                        
2119
                        List<Long> fileIds = dao.getAllFileIds();
2120
            logger.info("Total of " + fileIds.size() + " will be indexed");
2121
            int i = 0;
2122
                        for (Long id : fileIds) {
2123
                                postFileToSolr(solr, id);
2124
                i++;
2125
                        }
2126
            if (i % 100 == 0) {
2127
                solr.commit();
2128
                logger.debug("Sent commit to solr at file " + i);
2129
            }
2130
                        solr.optimize();
2131
                        solr.commit();
2132
            logger.info("Finished indexing of " + i + " files");
2133
            return "Finished indexing of " + i + " files";
2134
                } catch (IOException e) {
2135
                        throw new EJBException(e);
2136
                } catch (SolrServerException e) {
2137
                        throw new EJBException(e);
2138
                }
2139
        }
2140

    
2141
        @Override
2142
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2143
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2144
                        InsufficientPermissionsException, QuotaExceededException {
2145
                // Validate.
2146
                if (userId == null)
2147
                        throw new ObjectNotFoundException("No user specified");
2148
                if (folderId == null)
2149
                        throw new ObjectNotFoundException("No folder specified");
2150
                String contentType = mimeType;
2151
                if (StringUtils.isEmpty(mimeType))
2152
                        contentType = DEFAULT_MIME_TYPE;
2153
                if (StringUtils.isEmpty(name))
2154
                        throw new ObjectNotFoundException("No file name specified");
2155
                if (dao.existsFolderOrFile(folderId, name))
2156
                        throw new DuplicateNameException("A folder or file with the name '" + name +
2157
                                                "' already exists at this level");
2158

    
2159
                // Do the actual work.
2160
                Folder parent = null;
2161
                try {
2162
                        parent = dao.getEntityById(Folder.class, folderId);
2163
                } catch (final ObjectNotFoundException onfe) {
2164
                        // Supply a more accurate problem description.
2165
                        throw new ObjectNotFoundException("Parent folder not found");
2166
                }
2167
                final User owner = dao.getEntityById(User.class, userId);
2168
                if (!parent.hasWritePermission(owner))
2169
                        throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2170
                final FileHeader file = new FileHeader();
2171
                file.setName(name);
2172
                parent.addFile(file);
2173
                // set file owner to folder owner
2174
                file.setOwner(parent.getOwner());
2175
                //set file's readForAll value according to parent folder readForAll value
2176
                file.setReadForAll(parent.isReadForAll());
2177

    
2178
                final Date now = new Date();
2179
                final AuditInfo auditInfo = new AuditInfo();
2180
                auditInfo.setCreatedBy(owner);
2181
                auditInfo.setCreationDate(now);
2182
                auditInfo.setModifiedBy(owner);
2183
                auditInfo.setModificationDate(now);
2184
                file.setAuditInfo(auditInfo);
2185
                // TODO set the proper versioning flag on creation
2186
                file.setVersioned(false);
2187

    
2188
                for (final Permission p : parent.getPermissions()) {
2189
                        final Permission permission = new Permission();
2190
                        permission.setGroup(p.getGroup());
2191
                        permission.setUser(p.getUser());
2192
                        permission.setRead(p.getRead());
2193
                        permission.setWrite(p.getWrite());
2194
                        permission.setModifyACL(p.getModifyACL());
2195
                        file.addPermission(permission);
2196
                }
2197

    
2198
                // Create the file body.
2199
                try {
2200
                        createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2201
                } catch (FileNotFoundException e) {
2202
                        throw new GSSIOException(e);
2203
                }
2204
                touchParentFolders(parent, owner, new Date());
2205
                dao.flush();
2206
                indexFile(file.getId(), false);
2207

    
2208
                return file.getDTO();
2209
        }
2210

    
2211
        @Override
2212
        public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2213
                if (userId == null)
2214
                        throw new ObjectNotFoundException("No user specified");
2215
                if (fileId == null)
2216
                        throw new ObjectNotFoundException("No file specified");
2217
                String contentType = mimeType;
2218

    
2219
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2220

    
2221
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2222
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2223
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2224
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2225
                        contentType = identifyMimeType(file.getName());
2226

    
2227
                final User owner = dao.getEntityById(User.class, userId);
2228
                if (!file.hasWritePermission(owner))
2229
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2230
                final Date now = new Date();
2231
                final AuditInfo auditInfo = new AuditInfo();
2232
                auditInfo.setCreatedBy(owner);
2233
                auditInfo.setCreationDate(now);
2234
                auditInfo.setModifiedBy(owner);
2235
                auditInfo.setModificationDate(now);
2236
                try {
2237
                        createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2238
                } catch (FileNotFoundException e) {
2239
                        throw new GSSIOException(e);
2240
                }
2241
                Folder parent = file.getFolder();
2242
                touchParentFolders(parent, owner, new Date());
2243

    
2244
                indexFile(fileId, false);
2245
                return file.getDTO();
2246
        }
2247

    
2248
        /**
2249
         * Helper method for identifying mime type by examining the filename extension
2250
         *
2251
         * @param filename
2252
         * @return the mime type
2253
         */
2254
        private String identifyMimeType(String filename) {
2255
                if (filename.indexOf('.') != -1) {
2256
                        String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2257
                        if (".doc".equals(extension))
2258
                                return "application/msword";
2259
                        else if (".xls".equals(extension))
2260
                                return "application/vnd.ms-excel";
2261
                        else if (".ppt".equals(extension))
2262
                                return "application/vnd.ms-powerpoint";
2263
                        else if (".pdf".equals(extension))
2264
                                return "application/pdf";
2265
                        else if (".gif".equals(extension))
2266
                                return "image/gif";
2267
                        else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2268
                                return "image/jpeg";
2269
                        else if (".tiff".equals(extension) || ".tif".equals(extension))
2270
                                return "image/tiff";
2271
                        else if (".png".equals(extension))
2272
                                return "image/png";
2273
                        else if (".bmp".equals(extension))
2274
                                return "image/bmp";
2275
                }
2276
                // when all else fails assign the default mime type
2277
                return DEFAULT_MIME_TYPE;
2278
        }
2279

    
2280
        /**
2281
         * Helper method to create a new file body and attach it as the current body
2282
         * of the provided file header.
2283
         *
2284
         * @param name the original file name
2285
         * @param mimeType the content type
2286
         * @param fileSize the uploaded file size
2287
         * @param filePath the uploaded file full path
2288
         * @param header the file header that will be associated with the new body
2289
         * @param auditInfo the audit info
2290
         * @throws FileNotFoundException
2291
         * @throws QuotaExceededException
2292
         * @throws ObjectNotFoundException if the owner was not found
2293
         */
2294
        private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2295
                                FileHeader header, AuditInfo auditInfo)
2296
                        throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2297

    
2298
                long currentTotalSize = 0;
2299
                if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2300
                        currentTotalSize = header.getTotalSize();
2301
                Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2302
                if(quotaLeft < fileSize-currentTotalSize) {
2303
                        // quota exceeded -> delete the file
2304
                        deleteActualFile(filePath);
2305
                        throw new QuotaExceededException("Not enough free space available");
2306
                }
2307

    
2308
                FileBody body = new FileBody();
2309

    
2310
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2311
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2312
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2313
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2314
                        body.setMimeType(identifyMimeType(name));
2315
                else
2316
                        body.setMimeType(mimeType);
2317
                body.setAuditInfo(auditInfo);
2318
                body.setFileSize(fileSize);
2319
                body.setOriginalFilename(name);
2320
                body.setStoredFilePath(filePath);
2321
                //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2322
                if(!header.isVersioned() && header.getCurrentBody() != null){
2323
                        header.setCurrentBody(null);
2324
                        if (header.getBodies() != null) {
2325
                                Iterator<FileBody> it = header.getBodies().iterator();
2326
                                while(it.hasNext()){
2327
                                        FileBody bo = it.next();
2328
                                        deleteActualFile(bo.getStoredFilePath());
2329
                                        it.remove();
2330
                                        dao.delete(bo);
2331
                                }
2332
                        }
2333
                }
2334

    
2335
                dao.flush();
2336
                header.addBody(body);
2337
                header.setAuditInfo(auditInfo);
2338

    
2339
                dao.create(body);
2340
        }
2341

    
2342

    
2343
        @Override
2344
        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2345
        public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2346
                if (userId == null)
2347
                        throw new ObjectNotFoundException("No user specified");
2348
                User owner = dao.getEntityById(User.class, userId);
2349
                if(owner == null)
2350
                        throw new ObjectNotFoundException("No user specified");
2351
                long start = 0, end = 0;
2352
                if (logger.isDebugEnabled())
2353
                        start = System.currentTimeMillis();
2354
                File result = new File(generateRepositoryFilePath());
2355
                try {
2356
                        final FileOutputStream output = new FileOutputStream(result);
2357
                        final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2358
                        int n = 0;
2359

    
2360
                        while (-1 != (n = stream.read(buffer)))
2361
                                output.write(buffer, 0, n);
2362
                        output.close();
2363
                        stream.close();
2364
                } catch (IOException e) {
2365
                        if (!result.delete())
2366
                                logger.warn("Could not delete " + result.getPath());
2367
                        throw e;
2368
                }
2369
                if (logger.isDebugEnabled()) {
2370
                        end = System.currentTimeMillis();
2371
                        logger.debug("Time to upload: " + (end - start) + " (msec)");
2372
                }
2373
                return result;
2374
        }
2375

    
2376

    
2377
        @Override
2378
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2379

    
2380
                if (userId == null)
2381
                        throw new ObjectNotFoundException("No user specified");
2382
                User user = dao.getEntityById(User.class, userId);
2383
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2384
                if(status == null){
2385
                        status = new FileUploadStatus();
2386
                        status.setOwner(user);
2387
                        status.setFilename(filename);
2388
                        status.setBytesUploaded(bytesTransfered);
2389
                        status.setFileSize(fileSize);
2390
                        dao.create(status);
2391
                }
2392
                else{
2393
                        status.setBytesUploaded(bytesTransfered);
2394
                        status.setFileSize(fileSize);
2395
                        dao.update(status);
2396
                }
2397

    
2398
        }
2399

    
2400
        @Override
2401
        public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2402
                if (userId == null)
2403
                        throw new ObjectNotFoundException("No user specified");
2404
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2405
                if(status != null)
2406
                        dao.delete(status);
2407
        }
2408

    
2409
        @Override
2410
        public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2411
                return dao.getFileUploadStatus(userId, fileName);
2412
        }
2413

    
2414
        @Override
2415
        public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2416
                if (userId == null)
2417
                        throw new ObjectNotFoundException("No user specified");
2418
                if (folderId == null)
2419
                        throw new ObjectNotFoundException("No folder specified");
2420
                final User user = dao.getEntityById(User.class, userId);
2421
                final Folder folder = dao.getEntityById(Folder.class, folderId);
2422
                // Check permissions
2423
                if (!folder.hasReadPermission(user))
2424
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2425
                List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2426
                if (folder.hasReadPermission(user))
2427
                        for (Folder f : folder.getSubfolders())
2428
                                if (f.hasReadPermission(user) && !f.isDeleted())
2429
                                        subfolders.add(f.getDTO());
2430
                FolderDTO result = folder.getDTO();
2431
                result.setSubfolders(subfolders);
2432
                return folder.getDTO();
2433
        }
2434

    
2435
        @Override
2436
        public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2437
                if (userId == null)
2438
                        throw new ObjectNotFoundException("No user specified");
2439
                if (folderId == null)
2440
                        throw new ObjectNotFoundException("No folder specified");
2441
                User user = dao.getEntityById(User.class, callingUserId);
2442
                Folder folder = dao.getEntityById(Folder.class, folderId);
2443
                // Check permissions
2444
                if (!folder.hasReadPermission(user))
2445
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2446

    
2447
                FolderDTO result = folder.getDTO();
2448
                result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2449
                return result;
2450
        }
2451

    
2452
        @Override
2453
        public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2454
                        throws ObjectNotFoundException, InsufficientPermissionsException {
2455
                if (userId == null)
2456
                        throw new ObjectNotFoundException("No user specified");
2457
                if (fileId == null)
2458
                        throw new ObjectNotFoundException("No file specified");
2459
                if (version < 1)
2460
                        throw new ObjectNotFoundException("No valid version specified");
2461
                User user = dao.getEntityById(User.class, userId);
2462
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2463
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2464
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2465
                FileBody body = dao.getFileVersion(fileId, version);
2466
                return body.getDTO();
2467
        }
2468

    
2469
        @Override
2470
        public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2471
                if (userId == null)
2472
                        throw new ObjectNotFoundException("No user specified");
2473
                User user = dao.getEntityById(User.class, userId);
2474
                user.setAcceptedPolicy(isAccepted);
2475
                return user;
2476
        }
2477

    
2478
        @Override
2479
        public void updateAccounting(User user, Date date, long bandwidthDiff) {
2480
                dao.updateAccounting(user, date, bandwidthDiff);
2481
        }
2482

    
2483
        @Override
2484
        public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2485
                if (userId == null)
2486
                        throw new ObjectNotFoundException("No user specified");
2487
                if (folderId == null)
2488
                        throw new ObjectNotFoundException("No folder specified");
2489
                User user = dao.getEntityById(User.class, userId);
2490
                Folder folder = dao.getEntityById(Folder.class, folderId);
2491
                // Check permissions
2492
                if (!folder.hasReadPermission(user))
2493
                        return false;
2494
                return true;
2495
        }
2496

    
2497
        @Override
2498
        public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2499
                if (userId == null)
2500
                        throw new ObjectNotFoundException("No user specified");
2501
                User user = dao.getEntityById(User.class, userId);
2502
                user.generateWebDAVPassword();
2503
                return user.getWebDAVPassword();
2504
        }
2505

    
2506
        @Override
2507
        public Invitation findInvite(String code) {
2508
                if (code == null)
2509
                        return null;
2510
                return dao.findInvite(code);
2511
        }
2512

    
2513
        @Override
2514
        public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2515
                LDAPConnection lc = new LDAPConnection();
2516
        LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2517
        attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2518
        attributeSet.add(new LDAPAttribute("uid", username));
2519
        attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2520
        attributeSet.add(new LDAPAttribute("sn", lastname));
2521
        attributeSet.add(new LDAPAttribute("givenName", firstname));
2522
        attributeSet.add(new LDAPAttribute("mail", email));
2523
        attributeSet.add(new LDAPAttribute("userPassword", password));
2524
        String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2525
        LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2526
        try {
2527
                lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2528
                lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2529
                                getConfiguration().getString("bindPassword").getBytes("UTF8"));
2530
                lc.add(newEntry);
2531
                logger.info("Successfully added LDAP account: " + dn);
2532
                lc.disconnect();
2533
        } catch(LDAPException e) {
2534
                throw new RuntimeException(e);
2535
        } catch(UnsupportedEncodingException e) {
2536
                throw new RuntimeException(e);
2537
        }
2538

    
2539
        }
2540

    
2541
        @Override
2542
        public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2543
                User user = findUser(username);
2544
                if (user == null)
2545
                        throw new ObjectNotFoundException("The user was not found");
2546
                Invitation invite = findInvite(code);
2547
                if (invite.getUser() != null)
2548
                        throw new InvitationUsedException("This code has already been used");
2549
                invite.setUser(user);
2550
                UserClass couponClass = getCouponUserClass();
2551
                user.setUserClass(couponClass);
2552
                return couponClass;
2553
        }
2554

    
2555
        @Override
2556
        public UserClass getCouponUserClass() {
2557
                return dao.findCouponUserClass();
2558
        }
2559

    
2560
        /**
2561
         * Mark the folder as modified from the specified user and change it's modification date.
2562
         */
2563
        private void touchFolder(Folder f, User _user, Date now){
2564
                final AuditInfo auditInfo = f.getAuditInfo();
2565
                auditInfo.setModificationDate(now);
2566
                auditInfo.setModifiedBy(_user);
2567
                f.setAuditInfo(auditInfo);
2568
        }
2569

    
2570
        /**
2571
         * Mark the file as modified from the specified user and change it's modification date.
2572
         */
2573
        private void touchFile(FileHeader f, User _user, Date now){
2574
                final AuditInfo auditInfo = f.getAuditInfo();
2575
                auditInfo.setModificationDate(now);
2576
                auditInfo.setModifiedBy(_user);
2577
                f.setAuditInfo(auditInfo);
2578
        }
2579

    
2580
        /**
2581
         * Set the provided readForAll as the new readforAll value of the specified
2582
         * folder and sub-folders.
2583
         *
2584
         * @param user
2585
         * @param folder
2586
         * @param readForAll
2587
         * @throws ObjectNotFoundException
2588
         *
2589
         */
2590
        private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){
2591
                if (readForAll != null && user.equals(folder.getOwner())){
2592
                        folder.setReadForAll(readForAll);
2593
                        dao.update(folder);
2594
                        for (FileHeader file : folder.getFiles())
2595
                                file.setReadForAll(readForAll);
2596
                        if(readForAll)
2597
                                //only update subfolders when readforall is true. otherwise all sub-folders stay untouched
2598
                                for (Folder sub : folder.getSubfolders())
2599
                                        setFolderReadForAll(user, sub, readForAll);
2600

    
2601
                }
2602

    
2603
        }
2604
                
2605
        /**
2606
         * Update the userLogin with the values from the supplied object.
2607
         */
2608
        
2609
        public void addUserLogin(UserLogin userLogin) {
2610
                dao.update(userLogin);                
2611

    
2612
        }
2613
                
2614
        /**
2615
         * Retrieves the current session user login and the user's last login
2616
         * 
2617
         * @param userId
2618
         * @return a list of last two user logins
2619
         * @throws ObjectNotFoundException 
2620
         */
2621
        
2622
        public List<UserLogin> getUserLogins(Long userId) throws ObjectNotFoundException{
2623
                List<UserLogin> userLoginResults = new ArrayList<UserLogin>();                
2624
                userLoginResults = dao.getLoginsForUser(userId);        
2625
                if(userLoginResults.size() == 0)
2626
                        throw new ObjectNotFoundException("No userlogin found for the user");
2627
                //if the user logins for the first time lastLoginDate = currentLoginDate
2628
                if(userLoginResults.size()==1)
2629
                        userLoginResults.add(userLoginResults.get(0));
2630
                return userLoginResults;
2631
        }
2632
        
2633

    
2634
        @Override
2635
        public void postFileToSolr(CommonsHttpSolrServer solr, Long id) {
2636
                try {
2637
                        FileHeader file = dao.getFileForIndexing(id);
2638
                        FileBody body = file.getCurrentBody();
2639
                        String mime = body.getMimeType();
2640
                        boolean multipart = true;
2641
                        if (!mime.equals("application/pdf") 
2642
                                                && !mime.equals("text/plain")
2643
                                                && !mime.equals("text/html")
2644
                                                && !mime.endsWith("msword")
2645
                                                && !mime.endsWith("ms-excel")
2646
                                                && !mime.endsWith("powerpoint")
2647
                                                || (body.getFileSize() > getConfiguration().getLong("solrDocumentUploadLimitInKB") * 1024))
2648
                                multipart = false;
2649

    
2650
                        if (!multipart)
2651
                                sendMetaDataOnly(solr, file);
2652
                        else {
2653
                ContentStreamUpdateRequest solrRequest = new ContentStreamUpdateRequest(getConfiguration().getString("solr.rich.update.path"));
2654
                                solrRequest.setParam("literal.id", file.getId().toString());
2655
                                solrRequest.setParam("literal.name", file.getName());
2656
                                for (FileTag t : file.getFileTags()) {
2657
                                        solrRequest.getParams().add("literal.tag", t.getTag());
2658
                                }
2659
                for (Permission p : file.getPermissions()) {
2660
                    if (p.getRead()) {
2661
                        if (p.getUser() != null)
2662
                            solrRequest.setParam("literal.ureaders", p.getUser().getId().toString());
2663
                        else if (p.getGroup() != null)
2664
                            solrRequest.setParam("greaders", p.getGroup().getId().toString());
2665
                    }
2666
                }
2667
                File fsFile = new File(body.getStoredFilePath());
2668
                                solrRequest.addFile(fsFile);
2669
                                try {
2670
                                        solr.request(solrRequest);
2671
                                }
2672
                                catch (SolrException e) {
2673
                                        logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2674
                                        //Let 's try without the file
2675
                                        sendMetaDataOnly(solr, file);
2676
                                }
2677
                                catch (NullPointerException e) {
2678
                                        logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2679
                                        //Let 's try without the file
2680
                                        sendMetaDataOnly(solr, file);
2681
                                }
2682
                                catch (SolrServerException e) {
2683
                                        logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2684
                                        //Let 's try without the file
2685
                                        sendMetaDataOnly(solr, file);
2686
                                }
2687
                        }
2688
                } catch (MalformedURLException e) {
2689
                        throw new EJBException(e);
2690
                } catch (ObjectNotFoundException e) {
2691
                        logger.error("Indexing of file id " + id + " failed.", e);
2692
                } catch (SolrServerException e) {
2693
                        throw new EJBException(e);
2694
                } catch (IOException e) {
2695
                        throw new EJBException(e);
2696
                }
2697
        }
2698

    
2699
        private void sendMetaDataOnly(CommonsHttpSolrServer solr, FileHeader file) throws SolrServerException, IOException {
2700
                SolrInputDocument solrDoc = new SolrInputDocument();
2701
                solrDoc.addField("id", file.getId().toString());
2702
                solrDoc.addField("name", file.getName());
2703
                for (FileTag t : file.getFileTags()) {
2704
                        solrDoc.addField("tag", t.getTag());
2705
                }
2706
        for (Permission p : file.getPermissions()) {
2707
            if (p.getRead()) {
2708
                if (p.getUser() != null)
2709
                    solrDoc.addField("ureaders", p.getUser().getId());
2710
                else if (p.getGroup() != null)
2711
                    solrDoc.addField("greaders", p.getGroup().getId());
2712
            }
2713
        }
2714
                solr.add(solrDoc);
2715
        }
2716

    
2717
        private String tokenizeFilename(String filename){
2718
                StringBuffer result = new StringBuffer();
2719
                StringTokenizer tokenizer = new StringTokenizer(filename,"._");
2720
                while(tokenizer.hasMoreTokens()){
2721
                        result.append(tokenizer.nextToken());
2722
                        result.append(" ");
2723
                }
2724
                result.append(filename);
2725
                return result.toString();
2726
        }
2727

    
2728
        private String normalizeSearchQuery(String query) {
2729
                if (query.contains("*"))
2730
                        return query.toLowerCase().replace('ά', 'α').replace('έ', 'ε').replace('ί', 'ι').replace('ή', 'η').replace('ύ', 'υ')
2731
                                        .replace('ό', 'ο').replace('ς', 'σ').replace('ώ', 'ω').replace('ϊ', 'ι').replace('ϋ', 'υ');
2732
                else
2733
                        return query;
2734
        }
2735
        
2736
        private String escapeCharacters(String text) {
2737
                return text.replaceAll(":", "\\\\:");
2738
        }
2739
}