Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (98.2 kB)

1
/*
2
 * Copyright 2007, 2008, 2009, 2010  Electronic Business Systems Ltd.
3
 *
4
 * This file is part of GSS.
5
 *
6
 * GSS is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * GSS is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
18
 */
19
package gr.ebs.gss.server.ejb;
20

    
21
import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
22
import gr.ebs.gss.client.exceptions.DuplicateNameException;
23
import gr.ebs.gss.client.exceptions.GSSIOException;
24
import gr.ebs.gss.client.exceptions.InsufficientPermissionsException;
25
import gr.ebs.gss.client.exceptions.InvitationUsedException;
26
import gr.ebs.gss.client.exceptions.ObjectNotFoundException;
27
import gr.ebs.gss.client.exceptions.QuotaExceededException;
28
import gr.ebs.gss.server.domain.AuditInfo;
29
import gr.ebs.gss.server.domain.FileBody;
30
import gr.ebs.gss.server.domain.FileHeader;
31
import gr.ebs.gss.server.domain.FileTag;
32
import gr.ebs.gss.server.domain.FileUploadStatus;
33
import gr.ebs.gss.server.domain.Folder;
34
import gr.ebs.gss.server.domain.Group;
35
import gr.ebs.gss.server.domain.Invitation;
36
import gr.ebs.gss.server.domain.Nonce;
37
import gr.ebs.gss.server.domain.Permission;
38
import gr.ebs.gss.server.domain.User;
39
import gr.ebs.gss.server.domain.UserClass;
40
import gr.ebs.gss.server.domain.dto.FileBodyDTO;
41
import gr.ebs.gss.server.domain.dto.FileHeaderDTO;
42
import gr.ebs.gss.server.domain.dto.FolderDTO;
43
import gr.ebs.gss.server.domain.dto.GroupDTO;
44
import gr.ebs.gss.server.domain.dto.PermissionDTO;
45
import gr.ebs.gss.server.domain.dto.StatsDTO;
46
import gr.ebs.gss.server.domain.dto.UserDTO;
47

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

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

    
86
import org.apache.commons.lang.StringUtils;
87
import org.apache.commons.logging.Log;
88
import org.apache.commons.logging.LogFactory;
89
import org.apache.solr.client.solrj.SolrQuery;
90
import org.apache.solr.client.solrj.SolrServerException;
91
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
92
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
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 userId the ID of the current user
852
         * @param folderId the ID of the parent folder
853
         * @param name the name of the requested file
854
         * @return the file found
855
         * @throws ObjectNotFoundException if the specified folder or file was not
856
         *             found, with the exception message mentioning the precise
857
         *             problem
858
         */
859
        private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
860
                if (folderId == null)
861
                        throw new ObjectNotFoundException("No parent folder specified");
862
                if (StringUtils.isEmpty(name))
863
                        throw new ObjectNotFoundException("No file specified");
864

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

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

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

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

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

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

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

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

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

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

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

    
976
        }
977

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

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

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

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

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

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

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

    
1065
        }
1066

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1332
        }
1333

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1485
        }
1486

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

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

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

    
1555
        }
1556

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

    
1575
        }
1576

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

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

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

    
1616
        }
1617

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

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

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

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

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

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

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

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

    
1749
        }
1750

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

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

    
1787
        }
1788

    
1789
        @Override
1790
        public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
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
                List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1798
                for(FileHeader f : files)
1799
                        res.add(f.getDTO());
1800
                return res;
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
                List<FileHeader> result = new ArrayList<FileHeader>();
1812
                try {
1813
                        CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
1814
                        SolrQuery solrQuery = new SolrQuery(escapeCharacters(normalizeSearchQuery(query)));
1815
                        QueryResponse response = solr.query(solrQuery);
1816
                        SolrDocumentList results = response.getResults();
1817
                        User user = getUser(userId);
1818
                        for (SolrDocument d : results) {
1819
                                Long id = Long.valueOf((String) d.getFieldValue("id"));
1820
                                try {
1821
                                        FileHeader f = dao.getEntityById(FileHeader.class, id);
1822
                                        if (f.hasReadPermission(user))
1823
                                                result.add(f);
1824
                                } catch (ObjectNotFoundException e) {
1825
                                        logger.warn("Search result id " + id + " cannot be found", e);
1826
                                }
1827
                        }
1828
                } catch (MalformedURLException e) {
1829
                        logger.error(e);
1830
                        throw new EJBException(e);
1831
                } catch (SolrServerException e) {
1832
                        logger.error(e);
1833
                        throw new EJBException(e);
1834
                } catch (ObjectNotFoundException e) {
1835
                        logger.error(e);
1836
                        throw new EJBException(e);
1837
                }
1838
                return result;
1839
        }
1840

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

    
1848

    
1849
        }
1850

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

    
1858
        }
1859

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

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

    
1890
        }
1891

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

    
1897
        }
1898

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

    
1904
        }
1905

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

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

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

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

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

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

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

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

    
1996
                Folder parent = header.getFolder();
1997
                touchParentFolders(parent, user, new Date());
1998

    
1999
        }
2000

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

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

    
2020
        }
2021

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

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

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

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

    
2069
        @Override
2070
        public void rebuildSolrIndex() {
2071
                try {
2072
                        CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2073
                        solr.deleteByQuery("*:*");
2074
                        solr.commit();
2075
                        
2076
                        List<Long> fileIds = dao.getAllFileIds();
2077
                        for (Long id : fileIds) {
2078
                                postFileToSolr(id);
2079
                        }
2080
                        solr.optimize();
2081
                        solr.commit();
2082
                } catch (IOException e) {
2083
                        throw new EJBException(e);
2084
                } catch (SolrServerException e) {
2085
                        throw new EJBException(e);
2086
                }
2087
        }
2088

    
2089
        @Override
2090
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2091
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2092
                        InsufficientPermissionsException, QuotaExceededException {
2093
                // Validate.
2094
                if (userId == null)
2095
                        throw new ObjectNotFoundException("No user specified");
2096
                if (folderId == null)
2097
                        throw new ObjectNotFoundException("No folder specified");
2098
                String contentType = mimeType;
2099
                if (StringUtils.isEmpty(mimeType))
2100
                        contentType = DEFAULT_MIME_TYPE;
2101
                if (StringUtils.isEmpty(name))
2102
                        throw new ObjectNotFoundException("No file name specified");
2103
                if (dao.existsFolderOrFile(folderId, name))
2104
                        throw new DuplicateNameException("A folder or file with the name '" + name +
2105
                                                "' already exists at this level");
2106

    
2107
                // Do the actual work.
2108
                Folder parent = null;
2109
                try {
2110
                        parent = dao.getEntityById(Folder.class, folderId);
2111
                } catch (final ObjectNotFoundException onfe) {
2112
                        // Supply a more accurate problem description.
2113
                        throw new ObjectNotFoundException("Parent folder not found");
2114
                }
2115
                final User owner = dao.getEntityById(User.class, userId);
2116
                if (!parent.hasWritePermission(owner))
2117
                        throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2118
                final FileHeader file = new FileHeader();
2119
                file.setName(name);
2120
                parent.addFile(file);
2121
                // set file owner to folder owner
2122
                file.setOwner(parent.getOwner());
2123
                //set file's readForAll value according to parent folder readForAll value
2124
                file.setReadForAll(parent.isReadForAll());
2125

    
2126
                final Date now = new Date();
2127
                final AuditInfo auditInfo = new AuditInfo();
2128
                auditInfo.setCreatedBy(owner);
2129
                auditInfo.setCreationDate(now);
2130
                auditInfo.setModifiedBy(owner);
2131
                auditInfo.setModificationDate(now);
2132
                file.setAuditInfo(auditInfo);
2133
                // TODO set the proper versioning flag on creation
2134
                file.setVersioned(false);
2135

    
2136
                for (final Permission p : parent.getPermissions()) {
2137
                        final Permission permission = new Permission();
2138
                        permission.setGroup(p.getGroup());
2139
                        permission.setUser(p.getUser());
2140
                        permission.setRead(p.getRead());
2141
                        permission.setWrite(p.getWrite());
2142
                        permission.setModifyACL(p.getModifyACL());
2143
                        file.addPermission(permission);
2144
                }
2145

    
2146
                // Create the file body.
2147
                try {
2148
                        createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2149
                } catch (FileNotFoundException e) {
2150
                        throw new GSSIOException(e);
2151
                }
2152
                touchParentFolders(parent, owner, new Date());
2153
                dao.flush();
2154
                indexFile(file.getId(), false);
2155

    
2156
                return file.getDTO();
2157
        }
2158

    
2159
        @Override
2160
        public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2161
                if (userId == null)
2162
                        throw new ObjectNotFoundException("No user specified");
2163
                if (fileId == null)
2164
                        throw new ObjectNotFoundException("No file specified");
2165
                String contentType = mimeType;
2166

    
2167
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2168

    
2169
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2170
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2171
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2172
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2173
                        contentType = identifyMimeType(file.getName());
2174

    
2175
                final User owner = dao.getEntityById(User.class, userId);
2176
                if (!file.hasWritePermission(owner))
2177
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
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
                try {
2185
                        createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2186
                } catch (FileNotFoundException e) {
2187
                        throw new GSSIOException(e);
2188
                }
2189
                Folder parent = file.getFolder();
2190
                touchParentFolders(parent, owner, new Date());
2191

    
2192
                indexFile(fileId, false);
2193
                return file.getDTO();
2194
        }
2195

    
2196
        /**
2197
         * Helper method for identifying mime type by examining the filename extension
2198
         *
2199
         * @param filename
2200
         * @return the mime type
2201
         */
2202
        private String identifyMimeType(String filename) {
2203
                if (filename.indexOf('.') != -1) {
2204
                        String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2205
                        if (".doc".equals(extension))
2206
                                return "application/msword";
2207
                        else if (".xls".equals(extension))
2208
                                return "application/vnd.ms-excel";
2209
                        else if (".ppt".equals(extension))
2210
                                return "application/vnd.ms-powerpoint";
2211
                        else if (".pdf".equals(extension))
2212
                                return "application/pdf";
2213
                        else if (".gif".equals(extension))
2214
                                return "image/gif";
2215
                        else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2216
                                return "image/jpeg";
2217
                        else if (".tiff".equals(extension) || ".tif".equals(extension))
2218
                                return "image/tiff";
2219
                        else if (".png".equals(extension))
2220
                                return "image/png";
2221
                        else if (".bmp".equals(extension))
2222
                                return "image/bmp";
2223
                }
2224
                // when all else fails assign the default mime type
2225
                return DEFAULT_MIME_TYPE;
2226
        }
2227

    
2228
        /**
2229
         * Helper method to create a new file body and attach it as the current body
2230
         * of the provided file header.
2231
         *
2232
         * @param name the original file name
2233
         * @param mimeType the content type
2234
         * @param fileSize the uploaded file size
2235
         * @param filePath the uploaded file full path
2236
         * @param header the file header that will be associated with the new body
2237
         * @param auditInfo the audit info
2238
         * @param owner the owner of the file
2239
         * @throws FileNotFoundException
2240
         * @throws QuotaExceededException
2241
         * @throws ObjectNotFoundException if the owner was not found
2242
         */
2243
        private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2244
                                FileHeader header, AuditInfo auditInfo)
2245
                        throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2246

    
2247
                long currentTotalSize = 0;
2248
                if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2249
                        currentTotalSize = header.getTotalSize();
2250
                Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2251
                if(quotaLeft < fileSize-currentTotalSize) {
2252
                        // quota exceeded -> delete the file
2253
                        deleteActualFile(filePath);
2254
                        throw new QuotaExceededException("Not enough free space available");
2255
                }
2256

    
2257
                FileBody body = new FileBody();
2258

    
2259
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2260
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2261
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2262
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2263
                        body.setMimeType(identifyMimeType(name));
2264
                else
2265
                        body.setMimeType(mimeType);
2266
                body.setAuditInfo(auditInfo);
2267
                body.setFileSize(fileSize);
2268
                body.setOriginalFilename(name);
2269
                body.setStoredFilePath(filePath);
2270
                //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2271
                if(!header.isVersioned() && header.getCurrentBody() != null){
2272
                        header.setCurrentBody(null);
2273
                        if (header.getBodies() != null) {
2274
                                Iterator<FileBody> it = header.getBodies().iterator();
2275
                                while(it.hasNext()){
2276
                                        FileBody bo = it.next();
2277
                                        deleteActualFile(bo.getStoredFilePath());
2278
                                        it.remove();
2279
                                        dao.delete(bo);
2280
                                }
2281
                        }
2282
                }
2283

    
2284
                dao.flush();
2285
                header.addBody(body);
2286
                header.setAuditInfo(auditInfo);
2287

    
2288
                dao.create(body);
2289
        }
2290

    
2291

    
2292
        @Override
2293
        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2294
        public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2295
                if (userId == null)
2296
                        throw new ObjectNotFoundException("No user specified");
2297
                User owner = dao.getEntityById(User.class, userId);
2298
                if(owner == null)
2299
                        throw new ObjectNotFoundException("No user specified");
2300
                long start = 0, end = 0;
2301
                if (logger.isDebugEnabled())
2302
                        start = System.currentTimeMillis();
2303
                File result = new File(generateRepositoryFilePath());
2304
                try {
2305
                        final FileOutputStream output = new FileOutputStream(result);
2306
                        final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2307
                        int n = 0;
2308

    
2309
                        while (-1 != (n = stream.read(buffer)))
2310
                                output.write(buffer, 0, n);
2311
                        output.close();
2312
                        stream.close();
2313
                } catch (IOException e) {
2314
                        if (!result.delete())
2315
                                logger.warn("Could not delete " + result.getPath());
2316
                        throw e;
2317
                }
2318
                if (logger.isDebugEnabled()) {
2319
                        end = System.currentTimeMillis();
2320
                        logger.debug("Time to upload: " + (end - start) + " (msec)");
2321
                }
2322
                return result;
2323
        }
2324

    
2325

    
2326
        @Override
2327
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2328

    
2329
                if (userId == null)
2330
                        throw new ObjectNotFoundException("No user specified");
2331
                User user = dao.getEntityById(User.class, userId);
2332
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2333
                if(status == null){
2334
                        status = new FileUploadStatus();
2335
                        status.setOwner(user);
2336
                        status.setFilename(filename);
2337
                        status.setBytesUploaded(bytesTransfered);
2338
                        status.setFileSize(fileSize);
2339
                        dao.create(status);
2340
                }
2341
                else{
2342
                        status.setBytesUploaded(bytesTransfered);
2343
                        status.setFileSize(fileSize);
2344
                        dao.update(status);
2345
                }
2346

    
2347
        }
2348

    
2349
        @Override
2350
        public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2351
                if (userId == null)
2352
                        throw new ObjectNotFoundException("No user specified");
2353
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2354
                if(status != null)
2355
                        dao.delete(status);
2356
        }
2357

    
2358
        @Override
2359
        public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2360
                return dao.getFileUploadStatus(userId, fileName);
2361
        }
2362

    
2363
        @Override
2364
        public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2365
                if (userId == null)
2366
                        throw new ObjectNotFoundException("No user specified");
2367
                if (folderId == null)
2368
                        throw new ObjectNotFoundException("No folder specified");
2369
                final User user = dao.getEntityById(User.class, userId);
2370
                final Folder folder = dao.getEntityById(Folder.class, folderId);
2371
                // Check permissions
2372
                if (!folder.hasReadPermission(user))
2373
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2374
                List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2375
                if (folder.hasReadPermission(user))
2376
                        for (Folder f : folder.getSubfolders())
2377
                                if (f.hasReadPermission(user) && !f.isDeleted())
2378
                                        subfolders.add(f.getDTO());
2379
                FolderDTO result = folder.getDTO();
2380
                result.setSubfolders(subfolders);
2381
                return folder.getDTO();
2382
        }
2383

    
2384
        @Override
2385
        public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2386
                if (userId == null)
2387
                        throw new ObjectNotFoundException("No user specified");
2388
                if (folderId == null)
2389
                        throw new ObjectNotFoundException("No folder specified");
2390
                User user = dao.getEntityById(User.class, callingUserId);
2391
                Folder folder = dao.getEntityById(Folder.class, folderId);
2392
                // Check permissions
2393
                if (!folder.hasReadPermission(user))
2394
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2395

    
2396
                FolderDTO result = folder.getDTO();
2397
                result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2398
                return result;
2399
        }
2400

    
2401
        @Override
2402
        public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2403
                        throws ObjectNotFoundException, InsufficientPermissionsException {
2404
                if (userId == null)
2405
                        throw new ObjectNotFoundException("No user specified");
2406
                if (fileId == null)
2407
                        throw new ObjectNotFoundException("No file specified");
2408
                if (version < 1)
2409
                        throw new ObjectNotFoundException("No valid version specified");
2410
                User user = dao.getEntityById(User.class, userId);
2411
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2412
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2413
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2414
                FileBody body = dao.getFileVersion(fileId, version);
2415
                return body.getDTO();
2416
        }
2417

    
2418
        @Override
2419
        public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2420
                if (userId == null)
2421
                        throw new ObjectNotFoundException("No user specified");
2422
                User user = dao.getEntityById(User.class, userId);
2423
                user.setAcceptedPolicy(isAccepted);
2424
                return user;
2425
        }
2426

    
2427
        @Override
2428
        public void updateAccounting(User user, Date date, long bandwidthDiff) {
2429
                dao.updateAccounting(user, date, bandwidthDiff);
2430
        }
2431

    
2432
        @Override
2433
        public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2434
                if (userId == null)
2435
                        throw new ObjectNotFoundException("No user specified");
2436
                if (folderId == null)
2437
                        throw new ObjectNotFoundException("No folder specified");
2438
                User user = dao.getEntityById(User.class, userId);
2439
                Folder folder = dao.getEntityById(Folder.class, folderId);
2440
                // Check permissions
2441
                if (!folder.hasReadPermission(user))
2442
                        return false;
2443
                return true;
2444
        }
2445

    
2446
        @Override
2447
        public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2448
                if (userId == null)
2449
                        throw new ObjectNotFoundException("No user specified");
2450
                User user = dao.getEntityById(User.class, userId);
2451
                user.generateWebDAVPassword();
2452
                return user.getWebDAVPassword();
2453
        }
2454

    
2455
        @Override
2456
        public Invitation findInvite(String code) {
2457
                if (code == null)
2458
                        return null;
2459
                return dao.findInvite(code);
2460
        }
2461

    
2462
        @Override
2463
        public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2464
                LDAPConnection lc = new LDAPConnection();
2465
        LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2466
        attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2467
        attributeSet.add(new LDAPAttribute("uid", username));
2468
        attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2469
        attributeSet.add(new LDAPAttribute("sn", lastname));
2470
        attributeSet.add(new LDAPAttribute("givenName", firstname));
2471
        attributeSet.add(new LDAPAttribute("mail", email));
2472
        attributeSet.add(new LDAPAttribute("userPassword", password));
2473
        String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2474
        LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2475
        try {
2476
                lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2477
                lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2478
                                getConfiguration().getString("bindPassword").getBytes("UTF8"));
2479
                lc.add(newEntry);
2480
                logger.info("Successfully added LDAP account: " + dn);
2481
                lc.disconnect();
2482
        } catch(LDAPException e) {
2483
                throw new RuntimeException(e);
2484
        } catch(UnsupportedEncodingException e) {
2485
                throw new RuntimeException(e);
2486
        }
2487

    
2488
        }
2489

    
2490
        @Override
2491
        public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2492
                User user = findUser(username);
2493
                if (user == null)
2494
                        throw new ObjectNotFoundException("The user was not found");
2495
                Invitation invite = findInvite(code);
2496
                if (invite.getUser() != null)
2497
                        throw new InvitationUsedException("This code has already been used");
2498
                invite.setUser(user);
2499
                UserClass couponClass = getCouponUserClass();
2500
                user.setUserClass(couponClass);
2501
                return couponClass;
2502
        }
2503

    
2504
        @Override
2505
        public UserClass getCouponUserClass() {
2506
                return dao.findCouponUserClass();
2507
        }
2508

    
2509
        /**
2510
         * Mark the folder as modified from the specified user and change it's modification date.
2511
         */
2512
        private void touchFolder(Folder f, User _user, Date now){
2513
                final AuditInfo auditInfo = f.getAuditInfo();
2514
                auditInfo.setModificationDate(now);
2515
                auditInfo.setModifiedBy(_user);
2516
                f.setAuditInfo(auditInfo);
2517
        }
2518

    
2519
        /**
2520
         * Mark the file as modified from the specified user and change it's modification date.
2521
         */
2522
        private void touchFile(FileHeader f, User _user, Date now){
2523
                final AuditInfo auditInfo = f.getAuditInfo();
2524
                auditInfo.setModificationDate(now);
2525
                auditInfo.setModifiedBy(_user);
2526
                f.setAuditInfo(auditInfo);
2527
        }
2528

    
2529
        /**
2530
         * Set the provided readForAll as the new readforAll value of the specified
2531
         * folder and sub-folders.
2532
         *
2533
         * @param user
2534
         * @param folder
2535
         * @param readForAll
2536
         * @throws ObjectNotFoundException
2537
         *
2538
         */
2539
        private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){
2540
                if (readForAll != null && user.equals(folder.getOwner())){
2541
                        folder.setReadForAll(readForAll);
2542
                        dao.update(folder);
2543
                        for (FileHeader file : folder.getFiles())
2544
                                file.setReadForAll(readForAll);
2545
                        if(readForAll)
2546
                                //only update subfolders when readforall is true. otherwise all sub-folders stay untouched
2547
                                for (Folder sub : folder.getSubfolders())
2548
                                        setFolderReadForAll(user, sub, readForAll);
2549

    
2550
                }
2551

    
2552
        }
2553

    
2554
        @Override
2555
        public void postFileToSolr(Long id) {
2556
                try {
2557
                        FileHeader file = dao.getEntityById(FileHeader.class, id);
2558
                        FileBody body = file.getCurrentBody();
2559
                        String mime = body.getMimeType();
2560
                        boolean multipart = true;
2561
                        if (!mime.equals("application/pdf") 
2562
                                                && !mime.equals("text/plain")
2563
                                                && !mime.equals("text/html")
2564
                                                && !mime.endsWith("msword")
2565
                                                && !mime.endsWith("ms-excel")
2566
                                                && !mime.endsWith("powerpoint")
2567
                                                || (body.getFileSize() > getConfiguration().getLong("solrDocumentUploadLimitInKB") * 1024))
2568
                                multipart = false;
2569

    
2570
                        if (!multipart)
2571
                                sendMetaDataOnly(getConfiguration().getString("solr.url"), file);
2572
                        else {
2573
                                CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2574
                                ContentStreamUpdateRequest solrRequest = new ContentStreamUpdateRequest(getConfiguration().getString("solr.rich.update.path"));
2575
                                solrRequest.setParam("literal.id", file.getId().toString());
2576
                                solrRequest.setParam("literal.name", file.getName());
2577
                                for (FileTag t : file.getFileTags()) {
2578
                                        solrRequest.getParams().add("literal.tag", t.getTag());
2579
                                }
2580
                                solrRequest.addFile(new File(body.getStoredFilePath()));
2581
                                solrRequest.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
2582
                                try {
2583
                                        solr.request(solrRequest);
2584
                                }
2585
                                catch (SolrException e) {
2586
                                        logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2587
                                        //Let 's try without the file
2588
                                        sendMetaDataOnly(getConfiguration().getString("solr.url"), file);
2589
                                }
2590
                                catch (NullPointerException e) {
2591
                                        logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2592
                                        //Let 's try without the file
2593
                                        sendMetaDataOnly(getConfiguration().getString("solr.url"), file);
2594
                                }
2595
                                catch (SolrServerException e) {
2596
                                        logger.warn("File " + id + " failed with " + e.getLocalizedMessage() + ". Retrying without the file");
2597
                                        //Let 's try without the file
2598
                                        sendMetaDataOnly(getConfiguration().getString("solr.url"), file);
2599
                                }
2600
                        }
2601
                } catch (MalformedURLException e) {
2602
                        throw new EJBException(e);
2603
                } catch (ObjectNotFoundException e) {
2604
                        logger.error("Indexing of file id " + id + " failed.", e);
2605
                } catch (SolrServerException e) {
2606
                        throw new EJBException(e);
2607
                } catch (IOException e) {
2608
                        throw new EJBException(e);
2609
                }
2610
        }
2611

    
2612
        private void sendMetaDataOnly(String solrUrl, FileHeader file) throws SolrServerException, IOException {
2613
                CommonsHttpSolrServer solr = new CommonsHttpSolrServer(solrUrl);
2614
                SolrInputDocument solrDoc = new SolrInputDocument();
2615
                solrDoc.addField("id", file.getId().toString());
2616
                solrDoc.addField("name", file.getName());
2617
                for (FileTag t : file.getFileTags()) {
2618
                        solrDoc.addField("tag", t.getTag());
2619
                }
2620
                solr.add(solrDoc);
2621
                solr.commit();
2622
        }
2623

    
2624
        private String tokenizeFilename(String filename){
2625
                StringBuffer result = new StringBuffer();
2626
                StringTokenizer tokenizer = new StringTokenizer(filename,"._");
2627
                while(tokenizer.hasMoreTokens()){
2628
                        result.append(tokenizer.nextToken());
2629
                        result.append(" ");
2630
                }
2631
                result.append(filename);
2632
                return result.toString();
2633
        }
2634

    
2635
        private String normalizeSearchQuery(String query) {
2636
                if (query.contains("*"))
2637
                        return query.toLowerCase().replace('ά', 'α').replace('έ', 'ε').replace('ί', 'ι').replace('ή', 'η').replace('ύ', 'υ')
2638
                                        .replace('ό', 'ο').replace('ς', 'σ').replace('ώ', 'ω').replace('ϊ', 'ι').replace('ϋ', 'υ');
2639
                else
2640
                        return query;
2641
        }
2642
        
2643
        private String escapeCharacters(String text) {
2644
                return text.replaceAll(":", "\\\\:");
2645
        }
2646
}