Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (100.8 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

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

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

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

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

    
103
import com.novell.ldap.LDAPAttribute;
104
import com.novell.ldap.LDAPAttributeSet;
105
import com.novell.ldap.LDAPConnection;
106
import com.novell.ldap.LDAPEntry;
107
import com.novell.ldap.LDAPException;
108

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

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

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

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

    
138

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

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

    
158
        private Long getRootFolderId(Long userId) throws ObjectNotFoundException {
159
                if (userId == null)
160
                        throw new ObjectNotFoundException("No user specified");
161
                return dao.getRootFolderId(userId);
162
        }
163
        
164
        @Override
165
        public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
166
                if (userId == null)
167
                        throw new ObjectNotFoundException("No user specified");
168
                Folder folder = dao.getRootFolder(userId);
169
                return folder.getDTO();
170
        }
171

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

    
186
        @Override
187
        public User getUser(Long userId) throws ObjectNotFoundException {
188
                if (userId == null)
189
                        throw new ObjectNotFoundException("No user specified");
190
                return dao.getEntityById(User.class, userId);
191
        }
192

    
193
        @Override
194
        public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
195
                return getUser(userId).getDTO();
196
        }
197

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

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

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

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

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

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

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

    
281
                User creator = dao.getEntityById(User.class, userId);
282

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

    
294
                // Do the actual work.
295
                return createFolder(name, parent, creator);
296
        }
297

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

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

    
324
                if (parent != null)
325
                        for (Permission p : parent.getPermissions()) {
326
                                Permission permission = new Permission();
327
                                permission.setGroup(p.getGroup());
328
                                permission.setUser(p.getUser());
329
                                permission.setRead(p.getRead());
330
                                permission.setWrite(p.getWrite());
331
                                permission.setModifyACL(p.getModifyACL());
332
                                folder.addPermission(permission);
333
                        }
334
                else {
335
                        Permission permission = new Permission();
336
                        permission.setUser(creator);
337
                        permission.setRead(true);
338
                        permission.setWrite(true);
339
                        permission.setModifyACL(true);
340
                        folder.addPermission(permission);
341
                }
342

    
343
                if(parent != null)
344
                        folder.setReadForAll(parent.isReadForAll());
345

    
346
                dao.create(folder);
347
                return folder.getDTO();
348
        }
349

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

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

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

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

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

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

    
425
                Folder folder = dao.getEntityById(Folder.class, folderId);
426
                User user = dao.getEntityById(User.class, userId);
427
                if (folderName != null && !folder.hasWritePermission(user))
428
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
429
                if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
430
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
431
                // Check permissions for making file public.
432
                if (readForAll != null && !user.equals(folder.getOwner()))
433
                                throw new InsufficientPermissionsException("Only the owner can make a folder public or not public");
434

    
435
                Folder parent = folder.getParent();
436
                if (folderName != null) {
437
                        if (parent != null)
438
                                if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
439
                                        throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
440

    
441
                        // Do the actual modification.
442
                        folder.setName(folderName);
443
                }
444
                if (permissions != null)
445
                        setFolderPermissions(user, folder, permissions);
446
                if (readForAll != null)
447
                        setFolderReadForAll(user, folder, readForAll);
448
                folder.getAuditInfo().setModificationDate(new Date());
449
                folder.getAuditInfo().setModifiedBy(user);
450
                dao.update(folder);
451
                touchParentFolders(folder, user, new Date());
452
                // Re-index the folder contents if it was modified.
453
                if ((permissions != null && !permissions.isEmpty()) || readForAll != null) {
454
            indexFolder(folder);
455
        }
456

    
457
                return folder.getDTO();
458
        }
459

    
460
    private void indexFolder(Folder folder) {
461
        for (FileHeader fh : folder.getFiles())
462
            indexFile(fh.getId(), false);
463
        for (Folder f : folder.getSubfolders())
464
            indexFolder(f);
465
    }
466

    
467
        @Override
468
        public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
469
                // Validate.
470
                if (userId == null)
471
                        throw new ObjectNotFoundException("No user specified");
472
                if (StringUtils.isEmpty(name))
473
                        throw new ObjectNotFoundException("New group name is empty");
474
                if (name.indexOf('/')>=0)
475
                        throw new IllegalArgumentException("Character '/' is not allowed in group name");
476
                if (dao.existsGroup(userId, name))
477
                        throw new DuplicateNameException("A group with the name '" + name + "' already exists");
478

    
479
                // TODO: Check permissions
480

    
481
                final User owner = dao.getEntityById(User.class, userId);
482

    
483
                // Do the actual work.
484
                owner.createGroup(name);
485
        }
486

    
487
        @Override
488
        public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
489
                // Validate.
490
                if (userId == null)
491
                        throw new ObjectNotFoundException("No user specified");
492
                if (groupId == null)
493
                        throw new ObjectNotFoundException("No group specified");
494

    
495
                // Do the actual work.
496
                final User owner = dao.getEntityById(User.class, userId);
497
                final Group group = dao.getEntityById(Group.class, groupId);
498
                final Date now = new Date();
499
                // Only delete the group if actually owned by the user.
500
                if (group.getOwner().equals(owner)) {
501
                        List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
502
                        for (Folder f : folders){
503
                                f.getPermissions().removeAll(group.getPermissions());
504
                                touchFolder(f, owner, now);
505
                                for(FileHeader file : f.getFiles()){
506
                                        file.getPermissions().removeAll(group.getPermissions());
507
                                        touchFile(file, owner, now);
508
                                }
509
                        }
510
                        List<FileHeader> files = dao.getFilesPermittedForGroup(userId, groupId);
511
                        for(FileHeader h : files){
512
                                h.getPermissions().removeAll(group.getPermissions());
513
                                touchFile(h, owner, now);
514
                        }
515
                        owner.removeSpecifiedGroup(group);
516
                        dao.delete(group);
517
                }
518
                else throw new InsufficientPermissionsException("You are not the owner of this group");
519
        }
520

    
521
        @Override
522
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
523
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
524
                        InsufficientPermissionsException, QuotaExceededException {
525
                File file = null;
526
                try {
527
                        file = uploadFile(stream, userId);
528
                } catch ( IOException ioe) {
529
                        // Supply a more accurate problem description.
530
                        throw new GSSIOException("Problem creating file",ioe);
531
                }
532
                return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
533
        }
534

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

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

    
577

    
578

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

    
604
        @Override
605
        public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
606
                // Validate.
607
                if (userId == null)
608
                        throw new ObjectNotFoundException("No user specified");
609
                if (fileId == null)
610
                        throw new ObjectNotFoundException("No file specified");
611

    
612
                // Do the actual work.
613
                final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
614
                final Folder parent = file.getFolder();
615
                if (parent == null)
616
                        throw new ObjectNotFoundException("The specified file has no parent folder");
617
                final User user = dao.getEntityById(User.class, userId);
618
                if (!file.hasDeletePermission(user))
619
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
620
                for (final FileBody body : file.getBodies())
621
                        deleteActualFile(body.getStoredFilePath());
622
                dao.delete(file);
623
                touchParentFolders(parent, user, new Date());
624
                indexFile(fileId, true);
625
        }
626

    
627
        @Override
628
        public void deleteActualFile(String path) {
629
                if (path == null)
630
                        return;
631
                File file = new File(path);
632
                if (!file.delete())
633
                        logger.error("Could not delete file " + path);
634
        }
635

    
636
        @Override
637
        public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
638
                if (userId == null)
639
                        throw new ObjectNotFoundException("No user specified");
640
                if (fileHeaderId == null)
641
                        throw new ObjectNotFoundException("No file specified");
642
                if (StringUtils.isEmpty(tag))
643
                        throw new ObjectNotFoundException("Tag is empty");
644

    
645
                final User user = dao.getEntityById(User.class, userId);
646
                final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
647
                final Folder parent = fh.getFolder();
648
                if (parent == null)
649
                        throw new ObjectNotFoundException("The specified file has no parent folder");
650
                user.addTag(fh, tag);
651
                touchParentFolders(parent, user, new Date());
652
        }
653

    
654
        @Override
655
        public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
656
                return dao.getUserTags(userId);
657
        }
658

    
659
        @Override
660
        public void updateFile(Long userId, Long fileId, String name,
661
                                String tagSet, Date modificationDate, Boolean versioned,
662
                                Boolean readForAll,        Set<PermissionDTO> permissions)
663
                        throws DuplicateNameException, ObjectNotFoundException,        InsufficientPermissionsException {
664
                if (userId == null)
665
                        throw new ObjectNotFoundException("No user specified");
666
                if (fileId == null)
667
                        throw new ObjectNotFoundException("No file specified");
668
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
669
                final Folder parent = file.getFolder();
670
                if (parent == null)
671
                        throw new ObjectNotFoundException("The specified file has no parent folder");
672

    
673
                User user = dao.getEntityById(User.class, userId);
674
                // Check permissions for modifying the file metadata.
675
                if ((name != null || tagSet != null || modificationDate != null || versioned != null) && !file.hasWritePermission(user))
676
                        throw new InsufficientPermissionsException("User " + user.getId() +        " cannot update file " + file.getName() + "(" +        file.getId() + ")");
677
                // Check permissions for making file public.
678
                if (readForAll != null && !user.equals(file.getOwner()))
679
                                throw new InsufficientPermissionsException("Only the owner can make a file public or not public");
680
                // Check permissions for modifying the ACL.
681
                if(permissions != null && !permissions.isEmpty() &&        !file.hasModifyACLPermission(user))
682
                        throw new InsufficientPermissionsException("User " + user.getId() +        " cannot update the permissions on file " +        file.getName() + "(" + file.getId() + ")");
683

    
684
                if (name != null) {
685
                        // Do plain check for file already exists.
686
                        // Extreme concurrency case should be caught by constraint violation later.
687
                        if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
688
                        file.setName(name);
689
                }
690

    
691
                if (modificationDate != null)
692
                        file.getAuditInfo().setModificationDate(modificationDate);
693
                else
694
                        file.getAuditInfo().setModificationDate(new Date());
695
                file.getAuditInfo().setModifiedBy(user);
696

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

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

    
737
                touchParentFolders(parent, user, new Date());
738

    
739
                // Re-index the file if it was modified.
740
                if (name != null || tagSet != null || (permissions != null && !permissions.isEmpty()) || readForAll != null)
741
                        indexFile(fileId, false);
742
        }
743

    
744
        @Override
745
        public InputStream getFileContents(Long userId, Long fileId)
746
                        throws ObjectNotFoundException, InsufficientPermissionsException {
747
                if (userId == null)
748
                        throw new ObjectNotFoundException("No user specified");
749
                if (fileId == null)
750
                        throw new ObjectNotFoundException("No file specified");
751

    
752
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
753
                User user = dao.getEntityById(User.class, userId);
754
                if (!header.hasReadPermission(user)) {
755
                        logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
756
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
757
                }
758

    
759
                File f = new File(header.getCurrentBody().getStoredFilePath());
760
                try {
761
                        return new FileInputStream(f);
762
                } catch (FileNotFoundException e) {
763
                        logger.error("Could not locate the contents of file " + f.getAbsolutePath());
764
                        throw new ObjectNotFoundException("The file contents could not be located");
765
                }
766
        }
767

    
768
        /* (non-Javadoc)
769
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
770
         */
771
        @Override
772
        public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
773
                if (userId == null)
774
                        throw new ObjectNotFoundException("No user specified");
775
                if (fileId == null)
776
                        throw new ObjectNotFoundException("No file specified");
777
                if (bodyId == null)
778
                        throw new ObjectNotFoundException("No file specified");
779

    
780
                final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
781
                final FileBody body = dao.getEntityById(FileBody.class, bodyId);
782
                final User user = dao.getEntityById(User.class, userId);
783
                if (!header.hasReadPermission(user)) {
784
                        logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
785
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
786
                }
787

    
788
                File f = new File(body.getStoredFilePath());
789
                try {
790
                        return new FileInputStream(f);
791
                } catch (FileNotFoundException e) {
792
                        logger.error("Could not locate the contents of file " + f.getAbsolutePath());
793
                        throw new ObjectNotFoundException("The file contents could not be located");
794
                }
795
        }
796

    
797
        @Override
798
        public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
799
                if (userId == null)
800
                        throw new ObjectNotFoundException("No user specified");
801
                if (fileId == null)
802
                        throw new ObjectNotFoundException("No file specified");
803
                final User user = dao.getEntityById(User.class, userId);
804
                final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
805
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
806
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
807
                return file.getDTO();
808
        }
809

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

    
824
        @Override
825
        public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
826
                        throws ObjectNotFoundException {
827
                if (ownerId == null)
828
                        throw new ObjectNotFoundException("No user specified");
829
                if (StringUtils.isEmpty(path))
830
                        throw new ObjectNotFoundException("No path specified");
831

    
832
                User owner = dao.getEntityById(User.class, ownerId);
833
                List<String> pathElements = new ArrayList<String>();
834
                StringTokenizer st = new StringTokenizer(path, "/");
835
                while (st.hasMoreTokens())
836
                        pathElements.add(st.nextToken());
837
                if (pathElements.size() < 1)
838
                        return getRootFolder(owner.getId());
839
                // Store the last element, since it requires special handling.
840
                String lastElement = pathElements.remove(pathElements.size() - 1);
841
                
842
        //        Folder cursor = null;
843
                Long rootFolderId = getRootFolderId(owner.getId());
844
        Long cursorId = rootFolderId;
845
        if (pathElements.size() > 0)
846
            cursorId = dao.getFolderIdFromPath(rootFolderId, pathElements);
847

    
848
                // Use the lastElement to retrieve the actual resource.
849
                Object resource = null;
850
                try {
851
                        FileHeaderDTO file = getFile(cursorId, lastElement);
852
                        if (ignoreDeleted && file.isDeleted())
853
                                throw new ObjectNotFoundException("Resource not found");
854
                        resource = file;
855
                } catch (ObjectNotFoundException e) {
856
                        // Perhaps the requested resource is not a file, so
857
                        // check for folders as well.
858
                        FolderDTO folder = getFolder(cursorId, lastElement).getDTO();
859
                        if (ignoreDeleted && folder.isDeleted())
860
                                throw new ObjectNotFoundException("Resource not found");
861
                        resource = folder;
862
                }
863
                return resource;
864
        }
865

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

    
883
                FileHeader file = dao.getFile(folderId, name);
884
                return file.getDTO();
885
        }
886

    
887
        /**
888
         * Retrieve a folder for the specified user that has the specified name and
889
         * its parent folder has id equal to parentId.
890
         *
891
         * @param parentId the ID of the parent folder
892
         * @param name the name of the requested folder
893
         * @return the folder found
894
         * @throws ObjectNotFoundException if the specified folder or parent was not
895
         *             found, with the exception message mentioning the precise
896
         *             problem
897
         */
898
        private Folder getFolder(Long parentId, String name) throws ObjectNotFoundException {
899
                if (parentId == null)
900
                        throw new ObjectNotFoundException("No parent folder specified");
901
                if (StringUtils.isEmpty(name))
902
                        throw new ObjectNotFoundException("No folder specified");
903

    
904
                Folder folder = dao.getFolder(parentId, name);
905
                return folder;
906
        }
907

    
908
        private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
909
                File file = null;
910
                try {
911
                        file = uploadFile(resourceInputStream, userId);
912
                } catch ( IOException ioe) {
913
                        // Supply a more accurate problem description.
914
                        throw new GSSIOException("Problem creating file",ioe);
915
                }
916
                return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
917
        }
918

    
919
        @Override
920
        public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
921
                if (userId == null)
922
                        throw new ObjectNotFoundException("No user 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(userId, 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 copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
937
                if (userId == null)
938
                        throw new ObjectNotFoundException("No user specified");
939
                if (ownerId == null)
940
                        throw new ObjectNotFoundException("No owner specified");
941
                if (fileId == null)
942
                        throw new ObjectNotFoundException("No file specified");
943
                if (StringUtils.isEmpty(dest))
944
                        throw new ObjectNotFoundException("No destination specified");
945

    
946
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
947
                if (!(destination instanceof FolderDTO))
948
                        throw new ObjectNotFoundException("Destination parent folder not found");
949
                FolderDTO parent = (FolderDTO) destination;
950
                copyFile(userId, fileId, parent.getId(), getLastElement(dest));
951
        }
952

    
953
        @Override
954
        public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
955
                if (userId == null)
956
                        throw new ObjectNotFoundException("No user specified");
957
                if (fileId == null)
958
                        throw new ObjectNotFoundException("No file specified");
959
                if (destId == null)
960
                        throw new ObjectNotFoundException("No destination specified");
961
                if (StringUtils.isEmpty(destName))
962
                        throw new ObjectNotFoundException("No destination file name specified");
963

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

    
990
                } catch (FileNotFoundException e) {
991
                        throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
992
                }
993

    
994
        }
995

    
996
        @Override
997
        public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
998
                if (userId == null)
999
                        throw new ObjectNotFoundException("No user specified");
1000
                if (folderId == null)
1001
                        throw new ObjectNotFoundException("No folder specified");
1002
                if (StringUtils.isEmpty(dest))
1003
                        throw new ObjectNotFoundException("No destination specified");
1004

    
1005
                Object destination = getResourceAtPath(userId, getParentPath(dest), true);
1006
                if (!(destination instanceof FolderDTO))
1007
                        throw new ObjectNotFoundException("Destination folder not found");
1008
                FolderDTO parent = (FolderDTO) destination;
1009
                copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
1010
        }
1011

    
1012
        @Override
1013
        public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1014
                if (userId == null)
1015
                        throw new ObjectNotFoundException("No user specified");
1016
                if (folderId == null)
1017
                        throw new ObjectNotFoundException("No folder specified");
1018
                if (destId == null)
1019
                        throw new ObjectNotFoundException("No destination specified");
1020
                if (StringUtils.isEmpty(destName))
1021
                        throw new ObjectNotFoundException("No destination folder name specified");
1022
                Folder folder = dao.getEntityById(Folder.class, folderId);
1023
                Folder destination = dao.getEntityById(Folder.class, destId);
1024
                User user = dao.getEntityById(User.class, userId);
1025
                if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1026
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1027
                createFolder(user.getId(), destination.getId(), destName);
1028
        }
1029

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

    
1041
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1042
                if (!(destination instanceof FolderDTO))
1043
                        throw new ObjectNotFoundException("Destination folder not found");
1044
                FolderDTO parent = (FolderDTO) destination;
1045
                copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1046
        }
1047

    
1048
        @Override
1049
        public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1050
                if (userId == null)
1051
                        throw new ObjectNotFoundException("No user specified");
1052
                if (folderId == null)
1053
                        throw new ObjectNotFoundException("No folder specified");
1054
                if (destId == null)
1055
                        throw new ObjectNotFoundException("No destination specified");
1056
                if (StringUtils.isEmpty(destName))
1057
                        throw new ObjectNotFoundException("No destination folder name specified");
1058

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

    
1083
        }
1084

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

    
1111
        /**
1112
         * Get the last element in a path that denotes the file or folder name.
1113
         *
1114
         * @param path the provided path
1115
         * @return the last element in the path
1116
         */
1117
        private String getLastElement(String path) {
1118
                int lastDelimiter = path.lastIndexOf('/');
1119
                if (lastDelimiter == -1)
1120
                        // No path found.
1121
                        return path;
1122
                else if (lastDelimiter < path.length() - 1)
1123
                        // Return the part after the delimiter.
1124
                        return path.substring(lastDelimiter + 1);
1125
                else {
1126
                        // Remove the trailing delimiter and then recurse.
1127
                        String strippedTrail = path.substring(0, lastDelimiter);
1128
                        return getLastElement(strippedTrail);
1129
                }
1130
        }
1131

    
1132
        @Override
1133
        public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1134
                if (userId == null)
1135
                        throw new ObjectNotFoundException("No user specified");
1136
                if (fileId == null)
1137
                        throw new ObjectNotFoundException("No file specified");
1138

    
1139
                // Do the actual work.
1140
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1141
                Folder parent = file.getFolder();
1142
                if (parent == null)
1143
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1144
                User user = dao.getEntityById(User.class, userId);
1145
        trashFile(user, file);
1146
        touchParentFolders(parent, user, new Date());
1147
        }
1148

    
1149
    private void trashFile(User user, FileHeader file) throws InsufficientPermissionsException {
1150
        if (!file.hasDeletePermission(user))
1151
            throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1152

    
1153
        file.setDeleted(true);
1154
    }
1155

    
1156
        @Override
1157
        public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1158
                if (userId == null)
1159
                        throw new ObjectNotFoundException("No user specified");
1160
                if (ownerId == null)
1161
                        throw new ObjectNotFoundException("No owner specified");
1162
                if (fileId == null)
1163
                        throw new ObjectNotFoundException("No file specified");
1164
                if (StringUtils.isEmpty(dest))
1165
                        throw new ObjectNotFoundException("No destination specified");
1166

    
1167
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1168
                if (!(destination instanceof FolderDTO))
1169
                        throw new ObjectNotFoundException("Destination parent folder not found");
1170
                FolderDTO parent = (FolderDTO) destination;
1171
                moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1172
        }
1173

    
1174
        @Override
1175
        public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1176
                if (userId == null)
1177
                        throw new ObjectNotFoundException("No user specified");
1178
                if (fileId == null)
1179
                        throw new ObjectNotFoundException("No file specified");
1180
                if (destId == null)
1181
                        throw new ObjectNotFoundException("No destination specified");
1182
                if (StringUtils.isEmpty(destName))
1183
                        throw new ObjectNotFoundException("No destination file name specified");
1184

    
1185
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1186
                Folder source = file.getFolder();
1187
                Folder destination = dao.getEntityById(Folder.class, destId);
1188

    
1189
                User owner = dao.getEntityById(User.class, userId);
1190
                if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1191
                        throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1192

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

    
1224
        @Override
1225
        public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1226
                if (userId == null)
1227
                        throw new ObjectNotFoundException("No user specified");
1228
                if (ownerId == null)
1229
                        throw new ObjectNotFoundException("No owner specified");
1230
                if (folderId == null)
1231
                        throw new ObjectNotFoundException("No folder specified");
1232
                if (StringUtils.isEmpty(dest))
1233
                        throw new ObjectNotFoundException("No destination specified");
1234

    
1235
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1236
                if (!(destination instanceof FolderDTO))
1237
                        throw new ObjectNotFoundException("Destination parent folder not found");
1238
                FolderDTO parent = (FolderDTO) destination;
1239
                moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1240
        }
1241

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

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

    
1298
        @Override
1299
        public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1300
                // Validate.
1301
                if (userId == null)
1302
                        throw new ObjectNotFoundException("No user specified");
1303

    
1304
                // Do the actual work.
1305
                final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1306
                final List<FileHeader> files = dao.getDeletedFiles(userId);
1307
                for (final FileHeader f : files)
1308
                        result.add(f.getDTO());
1309
                return result;
1310
        }
1311

    
1312
        @Override
1313
        public void removeFileFromTrash(Long userId, Long fileId)
1314
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1315
                if (userId == null)
1316
                        throw new ObjectNotFoundException("No user specified");
1317
                if (fileId == null)
1318
                        throw new ObjectNotFoundException("No file specified");
1319

    
1320
                // Do the actual work.
1321
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1322
                Folder parent = file.getFolder();
1323
                if (parent == null)
1324
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1325
                User user = dao.getEntityById(User.class, userId);
1326
        untrashFile(user, file);
1327
                touchParentFolders(parent, user, new Date());
1328
        }
1329

    
1330
    private void untrashFile(User user, FileHeader file) throws InsufficientPermissionsException {
1331
        if (!file.hasDeletePermission(user))
1332
            throw new InsufficientPermissionsException("User " + user.getUsername() +
1333
                        " cannot restore file " + file.getName());
1334

    
1335
        file.setDeleted(false);
1336
    }
1337

    
1338
        @Override
1339
        public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1340
        if (userId == null)
1341
            throw new ObjectNotFoundException("No user specified");
1342
        if (folderId == null)
1343
            throw new ObjectNotFoundException("No folder specified");
1344
        Folder folder = dao.getEntityById(Folder.class, folderId);
1345
        User user = dao.getEntityById(User.class, userId);
1346
        trashFolder(user, folder);
1347
        touchParentFolders(folder, user, new Date());
1348
        }
1349

    
1350
    private void trashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException {
1351
        if (!folder.hasDeletePermission(user))
1352
            throw new InsufficientPermissionsException("You don't have the necessary permissions");
1353
        folder.setDeleted(true);
1354
        for (FileHeader file : folder.getFiles())
1355
            trashFile(user, file);
1356
        for (Folder subFolder : folder.getSubfolders())
1357
            trashFolder(user, subFolder);
1358
    }
1359

    
1360
        @Override
1361
        public void removeFolderFromTrash(Long userId, Long folderId)
1362
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1363
                if (userId == null)
1364
                        throw new ObjectNotFoundException("No user specified");
1365
                if (folderId == null)
1366
                        throw new ObjectNotFoundException("No folder specified");
1367
                Folder folder = dao.getEntityById(Folder.class, folderId);
1368
                User user = dao.getEntityById(User.class, userId);
1369
        untrashFolder(user, folder);
1370
                touchParentFolders(folder, user, new Date());
1371
        }
1372

    
1373
    private void untrashFolder(User user, Folder folder) throws ObjectNotFoundException, InsufficientPermissionsException {
1374
        if (!folder.hasDeletePermission(user))
1375
            throw new InsufficientPermissionsException("User " + user.getUsername() +
1376
                        " cannot restore folder " + folder.getName());
1377
        folder.setDeleted(false);
1378
        for (FileHeader file : folder.getFiles())
1379
            untrashFile(user, file);
1380
        for (Folder subFolder : folder.getSubfolders())
1381
            untrashFolder(user, subFolder);
1382
    }
1383

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

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

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

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

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

    
1444
        /**
1445
         * Get the default user class, which is the one with the lowest quota.
1446
         */
1447
        private UserClass getDefaultUserClass() {
1448
                return getUserClasses().get(0);
1449
        }
1450

    
1451
        @Override
1452
        public List<UserClass> getUserClasses() {
1453
                List<UserClass> classes = dao.getUserClasses();
1454
                // Create a default user class for first-time use. Afterwards, the
1455
                // admin should modify or add to the userclass table.
1456
                if (classes.size() == 0) {
1457
                        UserClass defaultClass = new UserClass();
1458
                        defaultClass.setName("default");
1459
                        Long defaultQuota = getConfiguration().getLong("quota", new Long(52428800L));
1460
                        defaultClass.setQuota(defaultQuota);
1461
                        dao.create(defaultClass);
1462
                        classes.add(defaultClass);
1463
                }
1464
                return classes;
1465
        }
1466

    
1467
        @Override
1468
        public User findUserByEmail(String email) {
1469
                return dao.findUserByEmail(email);
1470
        }
1471

    
1472
        @Override
1473
        public void updateUser(User user) {
1474
                dao.update(user);
1475
        }
1476

    
1477
        @Override
1478
        public User findUser(String username) {
1479
                if (username == null)
1480
                        return null;
1481
                return dao.findUser(username);
1482
        }
1483

    
1484
        @Override
1485
        public User updateUserToken(Long userId) throws ObjectNotFoundException {
1486
                if (userId == null)
1487
                        throw new ObjectNotFoundException("No user specified");
1488
                User user = dao.getEntityById(User.class, userId);
1489
                user.generateAuthToken();
1490
                return user;
1491
        }
1492

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

    
1514
        }
1515

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

    
1558
        private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1559
                Permission res = new Permission();
1560
                if (dto.getGroup() != null)
1561
                        res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1562
                else if (dto.getUser() != null)
1563
                        if (dto.getUser().getId() == null)
1564
                                res.setUser(dao.getUser(dto.getUser().getUsername()));
1565
                        else
1566
                                res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1567
                res.setRead(dto.hasRead());
1568
                res.setWrite(dto.hasWrite());
1569
                res.setModifyACL(dto.hasModifyACL());
1570
                return res;
1571
        }
1572

    
1573
        /* (non-Javadoc)
1574
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1575
         */
1576
        @Override
1577
        public List<UserDTO> getUsersByUserNameLike(String username) {
1578
                List<User> users = dao.getUsersByUserNameLike(username);
1579
                List<UserDTO> result = new ArrayList<UserDTO>();
1580
                for (User u : users)
1581
                        result.add(u.getDTO());
1582
                return result;
1583

    
1584
        }
1585

    
1586
        @Override
1587
        public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1588
                if (userId == null)
1589
                        throw new ObjectNotFoundException("No user specified");
1590
                if (groupId == null)
1591
                        throw new ObjectNotFoundException("No group specified");
1592
                if (userToAddId == null)
1593
                        throw new ObjectNotFoundException("No user to add specified");
1594
                User user = dao.getEntityById(User.class, userId);
1595
                Group group = dao.getEntityById(Group.class, groupId);
1596
                if (!group.getOwner().equals(user))
1597
                        throw new InsufficientPermissionsException();
1598
                User userToAdd = dao.getEntityById(User.class, userToAddId);
1599
                if (group.contains(userToAdd))
1600
                        throw new DuplicateNameException("User already exists in group");
1601
                group.getMembers().add(userToAdd);
1602
                dao.update(group);
1603

    
1604
        }
1605

    
1606
        @Override
1607
        public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1608
                if (userId == null)
1609
                        throw new ObjectNotFoundException("No user specified");
1610
                User user = dao.getEntityById(User.class, userId);
1611
                user.invalidateAuthToken();
1612
                return;
1613
        }
1614

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

    
1629
        @Override
1630
        public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1631
                if (userId == null)
1632
                        throw new ObjectNotFoundException("No user specified");
1633
                if (groupId == null)
1634
                        throw new ObjectNotFoundException("No group specified");
1635
                if (memberId == null)
1636
                        throw new ObjectNotFoundException("No member specified");
1637
                User owner = dao.getEntityById(User.class, userId);
1638
                Group group = dao.getEntityById(Group.class, groupId);
1639
                User member = dao.getEntityById(User.class, memberId);
1640
                if (!group.getOwner().equals(owner))
1641
                        throw new InsufficientPermissionsException("User is not the owner of the group");
1642
                group.removeMemberFromGroup(member);
1643
                dao.update(group);
1644

    
1645
        }
1646

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

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

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

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

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

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

    
1750
        @Override
1751
        public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1752
                if (ownerId == null)
1753
                        throw new ObjectNotFoundException("No owner specified");
1754
                if (callingUserId == null)
1755
                        throw new ObjectNotFoundException("No calling user specified");
1756
                List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1757
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1758
                for (FileHeader f : folders)
1759
                        result.add(f.getDTO());
1760
                return result;
1761
        }
1762

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

    
1778
        }
1779

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

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

    
1816
        }
1817

    
1818
        @Override
1819
        public List<FileHeader> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1820
        long startTime = System.currentTimeMillis();
1821
                if (userId == null)
1822
                        throw new ObjectNotFoundException("No user specified");
1823
                User user = getUser(userId);
1824
                if (query == null)
1825
                        throw new ObjectNotFoundException("No query specified");
1826
                List<FileHeader> files = search(user.getId(), query);
1827
                
1828
        long stopTime = System.currentTimeMillis();
1829
        logger.info("Total time: " + (stopTime - startTime));
1830
                return files;
1831
        }
1832

    
1833
        /**
1834
         * Performs the actuals search on the solr server and returns the results
1835
         *
1836
         * @param userId
1837
         * @param query
1838
         * @return a List of FileHeader objects
1839
         */
1840
        private List<FileHeader> search(Long userId, String query) {
1841
        final int maxRows = 100;
1842
                List<FileHeader> result = new ArrayList<FileHeader>();
1843
                try {
1844
                        CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
1845
            List<Group> groups = dao.getGroupsContainingUser(userId);
1846
            String constructedQuery = escapeCharacters(normalizeSearchQuery(query)) + " AND (public: true OR ureaders: " + userId;
1847
            if (!groups.isEmpty()) {
1848
                constructedQuery += " OR (";
1849
                for (int i=0; i<groups.size(); i++) {
1850
                    Group g = groups.get(i);
1851
                    constructedQuery += "greaders :" + g.getId();
1852
                    if (i < groups.size() - 1)
1853
                        constructedQuery += " OR ";
1854
                }
1855
                constructedQuery += ")";
1856
            }
1857
            constructedQuery += ")";
1858
                        SolrQuery solrQuery = new SolrQuery(constructedQuery);
1859
            solrQuery.setRows(maxRows);
1860
            long startTime = System.currentTimeMillis();
1861
                        QueryResponse response = solr.query(solrQuery);
1862
                        SolrDocumentList results = response.getResults();
1863
            if (results.getNumFound() > maxRows) {
1864
                solrQuery.setRows(Integer.valueOf((int) results.getNumFound()));
1865
                response = solr.query(solrQuery);
1866
                results = response.getResults();
1867
            }
1868
            long stopTime = System.currentTimeMillis();
1869
            logger.info("Search time:" +  (stopTime - startTime));
1870
                        User user = getUser(userId);
1871
            startTime = System.currentTimeMillis();
1872
                        for (SolrDocument d : results) {
1873
                                Long id = Long.valueOf((String) d.getFieldValue("id"));
1874
                                try {
1875
                                        FileHeader f = dao.getEntityById(FileHeader.class, id);
1876
                                        result.add(f);
1877
                                } catch (ObjectNotFoundException e) {
1878
                                        logger.warn("Search result id " + id + " cannot be found", e);
1879
                                }
1880
                        }
1881
            stopTime = System.currentTimeMillis();
1882
            logger.info("File loads: " + (stopTime - startTime));
1883
                } catch (MalformedURLException e) {
1884
                        logger.error(e);
1885
                        throw new EJBException(e);
1886
                } catch (SolrServerException e) {
1887
                        logger.error(e);
1888
                        throw new EJBException(e);
1889
                } catch (ObjectNotFoundException e) {
1890
                        logger.error(e);
1891
                        throw new EJBException(e);
1892
                }
1893
                return result;
1894
        }
1895

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

    
1903

    
1904
        }
1905

    
1906
        @Override
1907
        public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1908
                for(Long l : fileIds){
1909
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1910
                        moveFile(userId, l, destId, file.getName());
1911
                }
1912

    
1913
        }
1914

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

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

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

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

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

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

    
1981
        @Override
1982
        public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException,  GSSIOException, QuotaExceededException {
1983
                if (userId == null)
1984
                        throw new ObjectNotFoundException("No user specified");
1985
                if (fileId == null)
1986
                        throw new ObjectNotFoundException("No file specified");
1987
                User user = dao.getEntityById(User.class, userId);
1988
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1989
                if(!header.hasWritePermission(user))
1990
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1991
                FileBody body = dao.getFileVersion(fileId, version);
1992
                final File fileContents = new File(body.getStoredFilePath());
1993

    
1994
                try {
1995
                        updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
1996
                } catch (FileNotFoundException e) {
1997
                        throw new GSSIOException(e);
1998
                }
1999

    
2000
        }
2001

    
2002
        /* (non-Javadoc)
2003
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2004
         */
2005
        @Override
2006
        public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2007
                if (userId == null)
2008
                        throw new ObjectNotFoundException("No user specified");
2009
                if (fileId == null)
2010
                        throw new ObjectNotFoundException("No file specified");
2011
                User user = dao.getEntityById(User.class, userId);
2012
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2013
                if(!header.hasWritePermission(user))
2014
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2015
                Iterator<FileBody> it = header.getBodies().iterator();
2016
                while(it.hasNext()){
2017
                        FileBody body = it.next();
2018
                        if(!body.equals(header.getCurrentBody())){
2019
                                deleteActualFile(body.getStoredFilePath());
2020
                                it.remove();
2021
                                dao.delete(body);
2022
                        }
2023
                }
2024
                header.getCurrentBody().setVersion(1);
2025

    
2026
                Folder parent = header.getFolder();
2027
                touchParentFolders(parent, user, new Date());
2028
        }
2029

    
2030
        /**
2031
         * Gets the quota left for specified user ID.
2032
         */
2033
        private Long getQuotaLeft(Long userId) throws ObjectNotFoundException{
2034
                Long fileSize = dao.getFileSize(userId);
2035
                Long quota = getQuota(userId);
2036
                return quota - fileSize;
2037
        }
2038

    
2039
        /**
2040
         * Gets the quota for specified user ID.
2041
         */
2042
        private Long getQuota(Long userId) throws ObjectNotFoundException{
2043
                UserClass uc = getUser(userId).getUserClass();
2044
                if (uc == null)
2045
                        uc = getDefaultUserClass();
2046
                return uc.getQuota();
2047
        }
2048

    
2049
        @Override
2050
    @TransactionAttribute(TransactionAttributeType.NEVER)
2051
        public String rebuildSolrIndex() {
2052
                try {
2053
            CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2054
                        solr.deleteByQuery("*:*");
2055
                        solr.commit();
2056
            logger.info("Deleted everything in solr");
2057

    
2058
                        List<Long> fileIds = dao.getAllFileIds();
2059
            logger.info("Total of " + fileIds.size() + " will be indexed");
2060
            int i = 0;
2061
                        for (Long id : fileIds) {
2062
                                postFileToSolr(solr, id);
2063
                i++;
2064
                if (i % 10 == 0) {
2065
                    solr.commit();
2066
                    logger.info("Sent commit to solr at file " + i);
2067
                }
2068
                        }
2069
                        solr.optimize();
2070
                        solr.commit();
2071
            logger.info("Finished indexing of " + i + " files");
2072
            return "Finished indexing of " + i + " files";
2073
                } catch (IOException e) {
2074
                        throw new EJBException(e);
2075
                } catch (SolrServerException e) {
2076
                        throw new EJBException(e);
2077
                }
2078
        }
2079

    
2080
        @Override
2081
    @TransactionAttribute(TransactionAttributeType.NEVER)
2082
        public String refreshSolrIndex() {
2083
                try {
2084
                        CommonsHttpSolrServer solr = new CommonsHttpSolrServer(getConfiguration().getString("solr.url"));
2085
                        
2086
                        List<Long> fileIds = dao.getAllFileIds();
2087
            logger.info("Total of " + fileIds.size() + " will be indexed");
2088
            int i = 0;
2089
                        for (Long id : fileIds) {
2090
                                postFileToSolr(solr, id);
2091
                i++;
2092
                        }
2093
            if (i % 10 == 0) {
2094
                solr.commit();
2095
                logger.info("Sent commit to solr at file " + i);
2096
            }
2097
                        solr.optimize();
2098
                        solr.commit();
2099
            logger.info("Finished indexing of " + i + " files");
2100
            return "Finished indexing of " + i + " files";
2101
                } catch (IOException e) {
2102
                        throw new EJBException(e);
2103
                } catch (SolrServerException e) {
2104
                        throw new EJBException(e);
2105
                }
2106
        }
2107

    
2108
        @Override
2109
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2110
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2111
                        InsufficientPermissionsException, QuotaExceededException {
2112
                // Validate.
2113
                if (userId == null)
2114
                        throw new ObjectNotFoundException("No user specified");
2115
                if (folderId == null)
2116
                        throw new ObjectNotFoundException("No folder specified");
2117
                String contentType = mimeType;
2118
                if (StringUtils.isEmpty(mimeType))
2119
                        contentType = DEFAULT_MIME_TYPE;
2120
                if (StringUtils.isEmpty(name))
2121
                        throw new ObjectNotFoundException("No file name specified");
2122
                if (dao.existsFolderOrFile(folderId, name))
2123
                        throw new DuplicateNameException("A folder or file with the name '" + name +
2124
                                                "' already exists at this level");
2125

    
2126
                // Do the actual work.
2127
                Folder parent = null;
2128
                try {
2129
                        parent = dao.getEntityById(Folder.class, folderId);
2130
                } catch (final ObjectNotFoundException onfe) {
2131
                        // Supply a more accurate problem description.
2132
                        throw new ObjectNotFoundException("Parent folder not found");
2133
                }
2134
                final User owner = dao.getEntityById(User.class, userId);
2135
                if (!parent.hasWritePermission(owner))
2136
                        throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2137
                final FileHeader file = new FileHeader();
2138
                file.setName(name);
2139
                parent.addFile(file);
2140
                // set file owner to folder owner
2141
                file.setOwner(parent.getOwner());
2142
                //set file's readForAll value according to parent folder readForAll value
2143
                file.setReadForAll(parent.isReadForAll());
2144

    
2145
                final Date now = new Date();
2146
                final AuditInfo auditInfo = new AuditInfo();
2147
                auditInfo.setCreatedBy(owner);
2148
                auditInfo.setCreationDate(now);
2149
                auditInfo.setModifiedBy(owner);
2150
                auditInfo.setModificationDate(now);
2151
                file.setAuditInfo(auditInfo);
2152
                // TODO set the proper versioning flag on creation
2153
                file.setVersioned(false);
2154

    
2155
                for (final Permission p : parent.getPermissions()) {
2156
                        final Permission permission = new Permission();
2157
                        permission.setGroup(p.getGroup());
2158
                        permission.setUser(p.getUser());
2159
                        permission.setRead(p.getRead());
2160
                        permission.setWrite(p.getWrite());
2161
                        permission.setModifyACL(p.getModifyACL());
2162
                        file.addPermission(permission);
2163
                }
2164

    
2165
                // Create the file body.
2166
                try {
2167
                        createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2168
                } catch (FileNotFoundException e) {
2169
                        throw new GSSIOException(e);
2170
                }
2171
                touchParentFolders(parent, owner, new Date());
2172
                dao.flush();
2173
                indexFile(file.getId(), false);
2174

    
2175
                return file.getDTO();
2176
        }
2177

    
2178
        @Override
2179
        public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2180
                if (userId == null)
2181
                        throw new ObjectNotFoundException("No user specified");
2182
                if (fileId == null)
2183
                        throw new ObjectNotFoundException("No file specified");
2184
                String contentType = mimeType;
2185

    
2186
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2187

    
2188
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2189
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2190
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2191
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2192
                        contentType = identifyMimeType(file.getName());
2193

    
2194
                final User owner = dao.getEntityById(User.class, userId);
2195
                if (!file.hasWritePermission(owner))
2196
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2197
                final Date now = new Date();
2198
                final AuditInfo auditInfo = new AuditInfo();
2199
                auditInfo.setCreatedBy(owner);
2200
                auditInfo.setCreationDate(now);
2201
                auditInfo.setModifiedBy(owner);
2202
                auditInfo.setModificationDate(now);
2203
                try {
2204
                        createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2205
                } catch (FileNotFoundException e) {
2206
                        throw new GSSIOException(e);
2207
                }
2208
                Folder parent = file.getFolder();
2209
                touchParentFolders(parent, owner, new Date());
2210

    
2211
                indexFile(fileId, false);
2212
                return file.getDTO();
2213
        }
2214

    
2215
        /**
2216
         * Helper method for identifying mime type by examining the filename extension
2217
         *
2218
         * @param filename
2219
         * @return the mime type
2220
         */
2221
        private String identifyMimeType(String filename) {
2222
                if (filename.indexOf('.') != -1) {
2223
                        String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2224
                        if (".doc".equals(extension))
2225
                                return "application/msword";
2226
                        else if (".xls".equals(extension))
2227
                                return "application/vnd.ms-excel";
2228
                        else if (".ppt".equals(extension))
2229
                                return "application/vnd.ms-powerpoint";
2230
                        else if (".pdf".equals(extension))
2231
                                return "application/pdf";
2232
                        else if (".gif".equals(extension))
2233
                                return "image/gif";
2234
                        else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2235
                                return "image/jpeg";
2236
                        else if (".tiff".equals(extension) || ".tif".equals(extension))
2237
                                return "image/tiff";
2238
                        else if (".png".equals(extension))
2239
                                return "image/png";
2240
                        else if (".bmp".equals(extension))
2241
                                return "image/bmp";
2242
                }
2243
                // when all else fails assign the default mime type
2244
                return DEFAULT_MIME_TYPE;
2245
        }
2246

    
2247
        /**
2248
         * Helper method to create a new file body and attach it as the current body
2249
         * of the provided file header.
2250
         *
2251
         * @param name the original file name
2252
         * @param mimeType the content type
2253
         * @param fileSize the uploaded file size
2254
         * @param filePath the uploaded file full path
2255
         * @param header the file header that will be associated with the new body
2256
         * @param auditInfo the audit info
2257
         * @throws FileNotFoundException
2258
         * @throws QuotaExceededException
2259
         * @throws ObjectNotFoundException if the owner was not found
2260
         */
2261
        private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2262
                                FileHeader header, AuditInfo auditInfo)
2263
                        throws FileNotFoundException, QuotaExceededException, ObjectNotFoundException {
2264

    
2265
                long currentTotalSize = 0;
2266
                if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2267
                        currentTotalSize = header.getTotalSize();
2268
                Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2269
                if(quotaLeft < fileSize-currentTotalSize) {
2270
                        // quota exceeded -> delete the file
2271
                        deleteActualFile(filePath);
2272
                        throw new QuotaExceededException("Not enough free space available");
2273
                }
2274

    
2275
                FileBody body = new FileBody();
2276

    
2277
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2278
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2279
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2280
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2281
                        body.setMimeType(identifyMimeType(name));
2282
                else
2283
                        body.setMimeType(mimeType);
2284
                body.setAuditInfo(auditInfo);
2285
                body.setFileSize(fileSize);
2286
                body.setOriginalFilename(name);
2287
                body.setStoredFilePath(filePath);
2288
                //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2289
                if(!header.isVersioned() && header.getCurrentBody() != null){
2290
                        header.setCurrentBody(null);
2291
                        if (header.getBodies() != null) {
2292
                                Iterator<FileBody> it = header.getBodies().iterator();
2293
                                while(it.hasNext()){
2294
                                        FileBody bo = it.next();
2295
                                        deleteActualFile(bo.getStoredFilePath());
2296
                                        it.remove();
2297
                                        dao.delete(bo);
2298
                                }
2299
                        }
2300
                }
2301

    
2302
                dao.flush();
2303
                header.addBody(body);
2304
                header.setAuditInfo(auditInfo);
2305

    
2306
                dao.create(body);
2307
        }
2308

    
2309

    
2310
        @Override
2311
        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2312
        public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2313
                if (userId == null)
2314
                        throw new ObjectNotFoundException("No user specified");
2315
                User owner = dao.getEntityById(User.class, userId);
2316
                if(owner == null)
2317
                        throw new ObjectNotFoundException("No user specified");
2318
                long start = 0, end = 0;
2319
                if (logger.isDebugEnabled())
2320
                        start = System.currentTimeMillis();
2321
                File result = new File(generateRepositoryFilePath());
2322
                try {
2323
                        final FileOutputStream output = new FileOutputStream(result);
2324
                        final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2325
                        int n = 0;
2326

    
2327
                        while (-1 != (n = stream.read(buffer)))
2328
                                output.write(buffer, 0, n);
2329
                        output.close();
2330
                        stream.close();
2331
                } catch (IOException e) {
2332
                        if (!result.delete())
2333
                                logger.warn("Could not delete " + result.getPath());
2334
                        throw e;
2335
                }
2336
                if (logger.isDebugEnabled()) {
2337
                        end = System.currentTimeMillis();
2338
                        logger.debug("Time to upload: " + (end - start) + " (msec)");
2339
                }
2340
                return result;
2341
        }
2342

    
2343

    
2344
        @Override
2345
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2346

    
2347
                if (userId == null)
2348
                        throw new ObjectNotFoundException("No user specified");
2349
                User user = dao.getEntityById(User.class, userId);
2350
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2351
                if(status == null){
2352
                        status = new FileUploadStatus();
2353
                        status.setOwner(user);
2354
                        status.setFilename(filename);
2355
                        status.setBytesUploaded(bytesTransfered);
2356
                        status.setFileSize(fileSize);
2357
                        dao.create(status);
2358
                }
2359
                else{
2360
                        status.setBytesUploaded(bytesTransfered);
2361
                        status.setFileSize(fileSize);
2362
                        dao.update(status);
2363
                }
2364

    
2365
        }
2366

    
2367
        @Override
2368
        public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2369
                if (userId == null)
2370
                        throw new ObjectNotFoundException("No user specified");
2371
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2372
                if(status != null)
2373
                        dao.delete(status);
2374
        }
2375

    
2376
        @Override
2377
        public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2378
                return dao.getFileUploadStatus(userId, fileName);
2379
        }
2380

    
2381
        @Override
2382
        public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2383
                if (userId == null)
2384
                        throw new ObjectNotFoundException("No user specified");
2385
                if (folderId == null)
2386
                        throw new ObjectNotFoundException("No folder specified");
2387
                final User user = dao.getEntityById(User.class, userId);
2388
                final Folder folder = dao.getEntityById(Folder.class, folderId);
2389
                // Check permissions
2390
                if (!folder.hasReadPermission(user))
2391
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2392
                List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2393
                if (folder.hasReadPermission(user))
2394
                        for (Folder f : folder.getSubfolders())
2395
                                if (f.hasReadPermission(user) && !f.isDeleted())
2396
                                        subfolders.add(f.getDTO());
2397
                FolderDTO result = folder.getDTO();
2398
                result.setSubfolders(subfolders);
2399
                return folder.getDTO();
2400
        }
2401

    
2402
        @Override
2403
        public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2404
                if (userId == null)
2405
                        throw new ObjectNotFoundException("No user specified");
2406
                if (folderId == null)
2407
                        throw new ObjectNotFoundException("No folder specified");
2408
                User user = dao.getEntityById(User.class, callingUserId);
2409
                Folder folder = dao.getEntityById(Folder.class, folderId);
2410
                // Check permissions
2411
                if (!folder.hasReadPermission(user))
2412
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2413

    
2414
                FolderDTO result = folder.getDTO();
2415
                result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2416
                return result;
2417
        }
2418

    
2419
        @Override
2420
        public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2421
                        throws ObjectNotFoundException, InsufficientPermissionsException {
2422
                if (userId == null)
2423
                        throw new ObjectNotFoundException("No user specified");
2424
                if (fileId == null)
2425
                        throw new ObjectNotFoundException("No file specified");
2426
                if (version < 1)
2427
                        throw new ObjectNotFoundException("No valid version specified");
2428
                User user = dao.getEntityById(User.class, userId);
2429
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2430
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2431
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2432
                FileBody body = dao.getFileVersion(fileId, version);
2433
                return body.getDTO();
2434
        }
2435

    
2436
        @Override
2437
        public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2438
                if (userId == null)
2439
                        throw new ObjectNotFoundException("No user specified");
2440
                User user = dao.getEntityById(User.class, userId);
2441
                user.setAcceptedPolicy(isAccepted);
2442
                return user;
2443
        }
2444

    
2445
        @Override
2446
        public void updateAccounting(User user, Date date, long bandwidthDiff) {
2447
                dao.updateAccounting(user, date, bandwidthDiff);
2448
        }
2449

    
2450
        @Override
2451
        public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2452
                if (userId == null)
2453
                        throw new ObjectNotFoundException("No user specified");
2454
                if (folderId == null)
2455
                        throw new ObjectNotFoundException("No folder specified");
2456
                User user = dao.getEntityById(User.class, userId);
2457
                Folder folder = dao.getEntityById(Folder.class, folderId);
2458
                // Check permissions
2459
                if (!folder.hasReadPermission(user))
2460
                        return false;
2461
                return true;
2462
        }
2463

    
2464
        @Override
2465
        public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2466
                if (userId == null)
2467
                        throw new ObjectNotFoundException("No user specified");
2468
                User user = dao.getEntityById(User.class, userId);
2469
                user.generateWebDAVPassword();
2470
                return user.getWebDAVPassword();
2471
        }
2472

    
2473
        @Override
2474
        public Invitation findInvite(String code) {
2475
                if (code == null)
2476
                        return null;
2477
                return dao.findInvite(code);
2478
        }
2479

    
2480
        @Override
2481
        public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2482
                LDAPConnection lc = new LDAPConnection();
2483
        LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2484
        attributeSet.add(new LDAPAttribute("objectClass", getConfiguration().getStringArray("objectClass")));
2485
        attributeSet.add(new LDAPAttribute("uid", username));
2486
        attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2487
        attributeSet.add(new LDAPAttribute("sn", lastname));
2488
        attributeSet.add(new LDAPAttribute("givenName", firstname));
2489
        attributeSet.add(new LDAPAttribute("mail", email));
2490
        attributeSet.add(new LDAPAttribute("userPassword", password));
2491
        String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2492
        LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2493
        try {
2494
                lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2495
                lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2496
                                getConfiguration().getString("bindPassword").getBytes("UTF8"));
2497
                lc.add(newEntry);
2498
                logger.info("Successfully added LDAP account: " + dn);
2499
                lc.disconnect();
2500
        } catch(LDAPException e) {
2501
                throw new RuntimeException(e);
2502
        } catch(UnsupportedEncodingException e) {
2503
                throw new RuntimeException(e);
2504
        }
2505

    
2506
        }
2507

    
2508
        @Override
2509
        public UserClass upgradeUserClass(String username, String code) throws ObjectNotFoundException, InvitationUsedException {
2510
                User user = findUser(username);
2511
                if (user == null)
2512
                        throw new ObjectNotFoundException("The user was not found");
2513
                Invitation invite = findInvite(code);
2514
                if (invite.getUser() != null)
2515
                        throw new InvitationUsedException("This code has already been used");
2516
                invite.setUser(user);
2517
                UserClass couponClass = getCouponUserClass();
2518
                user.setUserClass(couponClass);
2519
                return couponClass;
2520
        }
2521

    
2522
        @Override
2523
        public UserClass getCouponUserClass() {
2524
                return dao.findCouponUserClass();
2525
        }
2526

    
2527
        /**
2528
         * Mark the folder as modified from the specified user and change it's modification date.
2529
         */
2530
        private void touchFolder(Folder f, User _user, Date now){
2531
                final AuditInfo auditInfo = f.getAuditInfo();
2532
                auditInfo.setModificationDate(now);
2533
                auditInfo.setModifiedBy(_user);
2534
                f.setAuditInfo(auditInfo);
2535
        }
2536

    
2537
        /**
2538
         * Mark the file as modified from the specified user and change it's modification date.
2539
         */
2540
        private void touchFile(FileHeader f, User _user, Date now){
2541
                final AuditInfo auditInfo = f.getAuditInfo();
2542
                auditInfo.setModificationDate(now);
2543
                auditInfo.setModifiedBy(_user);
2544
                f.setAuditInfo(auditInfo);
2545
        }
2546

    
2547
        /**
2548
         * Set the provided readForAll as the new readforAll value of the specified
2549
         * folder and sub-folders.
2550
         *
2551
         * @param user
2552
         * @param folder
2553
         * @param readForAll
2554
         * @throws ObjectNotFoundException
2555
         *
2556
         */
2557
        private void setFolderReadForAll(User user, Folder folder, Boolean readForAll){
2558
                if (readForAll != null && user.equals(folder.getOwner())){
2559
                        folder.setReadForAll(readForAll);
2560
                        dao.update(folder);
2561
                        for (FileHeader file : folder.getFiles())
2562
                                file.setReadForAll(readForAll);
2563
                        if(readForAll)
2564
                                //only update subfolders when readforall is true. otherwise all sub-folders stay untouched
2565
                                for (Folder sub : folder.getSubfolders())
2566
                                        setFolderReadForAll(user, sub, readForAll);
2567

    
2568
                }
2569

    
2570
        }
2571
                
2572
        /**
2573
         * Update the userLogin with the values from the supplied object.
2574
         */
2575
        
2576
        public void addUserLogin(UserLogin userLogin) {
2577
                dao.update(userLogin);                
2578

    
2579
        }
2580
                
2581
        /**
2582
         * Retrieves the current session user login and the user's last login
2583
         * 
2584
         * @param userId
2585
         * @return a list of last two user logins
2586
         * @throws ObjectNotFoundException 
2587
         */
2588
        
2589
        public List<UserLogin> getLastUserLogins(Long userId) throws ObjectNotFoundException{
2590
                List<UserLogin> userLoginResults = new ArrayList<UserLogin>();                
2591
                userLoginResults = dao.getLoginsForUser(userId);        
2592
                if(userLoginResults.size() == 0)
2593
                        throw new ObjectNotFoundException("No userlogin found for the user");
2594
                //if the user logins for the first time lastLoginDate = currentLoginDate
2595
                if(userLoginResults.size()==1)
2596
                        userLoginResults.add(userLoginResults.get(0));
2597
                return userLoginResults;
2598
        }
2599
        
2600

    
2601
        @Override
2602
        public void postFileToSolr(CommonsHttpSolrServer solr, Long id) {
2603
                try {
2604
                        FileHeader file = dao.getFileForIndexing(id);
2605
                        FileBody body = file.getCurrentBody();
2606
                        String mime = body.getMimeType();
2607
                        boolean multipart = true;
2608
                        if (!mime.equals("application/pdf") 
2609
                                                && !mime.equals("text/plain")
2610
                                                && !mime.equals("text/html")
2611
                                                && !mime.endsWith("msword")
2612
                                                && !mime.endsWith("ms-excel")
2613
                                                && !mime.endsWith("powerpoint")
2614
                                                || (body.getFileSize() > getConfiguration().getLong("solrDocumentUploadLimitInKB") * 1024))
2615
                                multipart = false;
2616

    
2617
                        if (!multipart)
2618
                                sendMetaDataOnly(solr, file);
2619
                        else {
2620
                ContentStreamUpdateRequest solrRequest = new ContentStreamUpdateRequest(getConfiguration().getString("solr.rich.update.path"));
2621
                                solrRequest.setParam("literal.id", file.getId().toString());
2622
                                solrRequest.setParam("literal.name", file.getName());
2623
                                for (FileTag t : file.getFileTags()) {
2624
                                        solrRequest.getParams().add("literal.tag", t.getTag());
2625
                                }
2626
                for (Permission p : file.getPermissions()) {
2627
                    if (p.getRead()) {
2628
                        if (p.getUser() != null)
2629
                            solrRequest.setParam("literal.ureaders", p.getUser().getId().toString());
2630
                        else if (p.getGroup() != null)
2631
                            solrRequest.setParam("literal.greaders", p.getGroup().getId().toString());
2632
                    }
2633
                }
2634
                solrRequest.setParam("literal.owner", file.getOwner().getId().toString());
2635
                solrRequest.setParam("literal.public", String.valueOf(file.isReadForAll()));
2636
                File fsFile = new File(body.getStoredFilePath());
2637
                                solrRequest.addFile(fsFile);
2638
                                try {
2639
                                        solr.request(solrRequest);
2640
                                }
2641
                                catch (SolrException e) {
2642
                                        logger.warn("File " + id + " failed with SolrException: " + e.getLocalizedMessage() + ". Retrying without the file");
2643
                                        //Let 's try without the file
2644
                                        sendMetaDataOnly(solr, file);
2645
                                }
2646
                                catch (NullPointerException e) {
2647
                                        logger.warn("File " + id + " failed with NullPointerException: " + e.getLocalizedMessage() + ". Retrying without the file");
2648
                                        //Let 's try without the file
2649
                                        sendMetaDataOnly(solr, file);
2650
                                }
2651
                                catch (SolrServerException e) {
2652
                                        logger.warn("File " + id + " failed with SolrServerException: " + e.getLocalizedMessage() + ". Retrying without the file");
2653
                                        //Let 's try without the file
2654
                                        sendMetaDataOnly(solr, file);
2655
                                }
2656
                        }
2657
                } catch (MalformedURLException e) {
2658
                        throw new EJBException(e);
2659
                } catch (ObjectNotFoundException e) {
2660
                        logger.error("Indexing of file id " + id + " failed.", e);
2661
                } catch (SolrServerException e) {
2662
                        throw new EJBException(e);
2663
                } catch (IOException e) {
2664
                        throw new EJBException(e);
2665
                }
2666
        }
2667

    
2668
        private void sendMetaDataOnly(CommonsHttpSolrServer solr, FileHeader file) throws SolrServerException, IOException {
2669
                SolrInputDocument solrDoc = new SolrInputDocument();
2670
                solrDoc.addField("id", file.getId().toString());
2671
                solrDoc.addField("name", file.getName());
2672
                for (FileTag t : file.getFileTags()) {
2673
                        solrDoc.addField("tag", t.getTag());
2674
                }
2675
        for (Permission p : file.getPermissions()) {
2676
            if (p.getRead()) {
2677
                if (p.getUser() != null)
2678
                    solrDoc.addField("ureaders", p.getUser().getId());
2679
                else if (p.getGroup() != null)
2680
                    solrDoc.addField("greaders", p.getGroup().getId());
2681
            }
2682
        }
2683
        solrDoc.addField("owner", file.getOwner().getId());
2684
        solrDoc.addField("public", file.isReadForAll());
2685
                solr.add(solrDoc);
2686
        }
2687

    
2688
        private String tokenizeFilename(String filename){
2689
                StringBuffer result = new StringBuffer();
2690
                StringTokenizer tokenizer = new StringTokenizer(filename,"._");
2691
                while(tokenizer.hasMoreTokens()){
2692
                        result.append(tokenizer.nextToken());
2693
                        result.append(" ");
2694
                }
2695
                result.append(filename);
2696
                return result.toString();
2697
        }
2698

    
2699
        private String normalizeSearchQuery(String query) {
2700
                if (query.contains("*"))
2701
                        return query.toLowerCase().replace('ά', 'α').replace('έ', 'ε').replace('ί', 'ι').replace('ή', 'η').replace('ύ', 'υ')
2702
                                        .replace('ό', 'ο').replace('ς', 'σ').replace('ώ', 'ω').replace('ϊ', 'ι').replace('ϋ', 'υ');
2703
                else
2704
                        return query;
2705
        }
2706
        
2707
        private String escapeCharacters(String text) {
2708
                return text.replaceAll(":", "\\\\:");
2709
        }
2710
}