Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (99.3 kB)

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

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

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

    
65
import javax.ejb.EJB;
66
import javax.ejb.EJBException;
67
import javax.ejb.EJBTransactionRolledbackException;
68
import javax.ejb.Stateless;
69
import javax.ejb.TransactionAttribute;
70
import javax.ejb.TransactionAttributeType;
71
import javax.jms.Connection;
72
import javax.jms.ConnectionFactory;
73
import javax.jms.JMSException;
74
import javax.jms.MapMessage;
75
import javax.jms.MessageProducer;
76
import javax.jms.Queue;
77
import javax.jms.QueueConnectionFactory;
78
import javax.jms.Session;
79
import javax.naming.Context;
80
import javax.naming.InitialContext;
81
import javax.naming.NamingException;
82
import javax.persistence.PersistenceException;
83
import javax.xml.parsers.DocumentBuilder;
84
import javax.xml.parsers.DocumentBuilderFactory;
85
import javax.xml.parsers.ParserConfigurationException;
86
import javax.xml.transform.OutputKeys;
87
import javax.xml.transform.Transformer;
88
import javax.xml.transform.TransformerConfigurationException;
89
import javax.xml.transform.TransformerException;
90
import javax.xml.transform.TransformerFactory;
91
import javax.xml.transform.dom.DOMSource;
92
import javax.xml.transform.stream.StreamResult;
93

    
94
import org.apache.commons.httpclient.HttpClient;
95
import org.apache.commons.httpclient.HttpException;
96
import org.apache.commons.httpclient.NameValuePair;
97
import org.apache.commons.httpclient.methods.GetMethod;
98
import org.apache.commons.httpclient.methods.PostMethod;
99
import org.apache.commons.httpclient.methods.StringRequestEntity;
100
import org.apache.commons.lang.StringUtils;
101
import org.apache.commons.logging.Log;
102
import org.apache.commons.logging.LogFactory;
103
import org.hibernate.exception.ConstraintViolationException;
104
import org.w3c.dom.DOMException;
105
import org.w3c.dom.Document;
106
import org.w3c.dom.Node;
107
import org.w3c.dom.NodeList;
108
import org.xml.sax.SAXException;
109

    
110
import com.novell.ldap.LDAPAttribute;
111
import com.novell.ldap.LDAPAttributeSet;
112
import com.novell.ldap.LDAPConnection;
113
import com.novell.ldap.LDAPEntry;
114
import com.novell.ldap.LDAPException;
115

    
116
/**
117
 * The concrete implementation of the ExternalAPI interface.
118
 *
119
 * @author past
120
 */
121
@Stateless
122
public class ExternalAPIBean implements ExternalAPI, ExternalAPIRemote {
123
        /**
124
         * The default MIME type for files without an explicit one.
125
         */
126
        private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
127

    
128
        /**
129
         * The size of the buffer that is used to temporarily store chunks of
130
         * uploaded files, while storing them to the file repository.
131
         */
132
        private static final int UPLOAD_BUFFER_SIZE = 1024 * 4;
133

    
134
        /**
135
         * The logger.
136
         */
137
        private static Log logger = LogFactory.getLog(ExternalAPIBean.class);
138

    
139
        /**
140
         * Injected reference to the GSSDAO data access facade.
141
         */
142
        @EJB
143
        private GSSDAO dao;
144

    
145

    
146
        /**
147
         * A cached random number generator for creating unique filenames.
148
         */
149
        private static Random random = new Random();
150

    
151
        /**
152
         * Mark the folder and all of its parent folders as modified from the specified user.
153
         */
154
        private void touchParentFolders(Folder folder, User user, Date date) {
155
                Folder f = folder;
156
                while (f != null) {
157
                        AuditInfo ai = f.getAuditInfo();
158
                        ai.setModifiedBy(user);
159
                        ai.setModificationDate(date);
160
                        f.setAuditInfo(ai);
161
                        f = f.getParent();
162
                }
163
        }
164

    
165
        @Override
166
        public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
167
                if (userId == null)
168
                        throw new ObjectNotFoundException("No user specified");
169
                Folder folder = dao.getRootFolder(userId);
170
                return folder.getDTO();
171
        }
172

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

    
187
        /* (non-Javadoc)
188
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUser(java.lang.Long)
189
         */
190
        public User getUser(Long userId) throws ObjectNotFoundException {
191
                if (userId == null)
192
                        throw new ObjectNotFoundException("No user specified");
193
                return dao.getEntityById(User.class, userId);
194
        }
195

    
196
        /* (non-Javadoc)
197
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserDTO(java.lang.Long)
198
         */
199
        public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
200
                return getUser(userId).getDTO();
201
        }
202

    
203
        /*
204
         * (non-Javadoc)
205
         *
206
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroup(java.lang.Long)
207
         */
208
        public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
209
                if (groupId == null)
210
                        throw new ObjectNotFoundException("No group specified");
211
                final Group group = dao.getEntityById(Group.class, groupId);
212
                return group.getDTO();
213
        }
214

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

    
229
        /*
230
         * (non-Javadoc)
231
         *
232
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroups(java.lang.Long)
233
         */
234
        public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
235
                if (userId == null)
236
                        throw new ObjectNotFoundException("No user specified");
237
                final List<Group> groups = dao.getGroups(userId);
238
                final List<GroupDTO> result = new ArrayList<GroupDTO>();
239
                for (final Group g : groups)
240
                        result.add(g.getDTO());
241
                return result;
242
        }
243

    
244
        @Override
245
        public List<FileHeaderDTO> getFiles(Long userId, Long folderId, boolean ignoreDeleted)
246
                        throws ObjectNotFoundException, InsufficientPermissionsException {
247
                // Validate.
248
                if (userId == null)
249
                        throw new ObjectNotFoundException("No user specified");
250
                if (folderId == null)
251
                        throw new ObjectNotFoundException("No folder specified");
252
                User user = dao.getEntityById(User.class, userId);
253
                Folder folder = dao.getEntityById(Folder.class, folderId);
254
                if (!folder.hasReadPermission(user))
255
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
256
                // Do the actual work.
257
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
258
                List<FileHeader> files = dao.getFiles(folderId, userId, ignoreDeleted);
259
                for (FileHeader f : files)
260
                        result.add(f.getDTO());
261
                return result;
262
        }
263

    
264
        /*
265
         * (non-Javadoc)
266
         *
267
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsers(java.lang.Long,
268
         *      java.lang.Long)
269
         */
270
        public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
271
                // Validate.
272
                if (userId == null)
273
                        throw new ObjectNotFoundException("No user specified");
274
                if (groupId == null)
275
                        throw new ObjectNotFoundException("No group specified");
276

    
277
                // Do the actual work.
278
                final List<User> users = dao.getUsers(groupId);
279
                final List<UserDTO> result = new ArrayList<UserDTO>();
280
                for (final User u : users)
281
                        result.add(u.getDTO());
282
                return result;
283
        }
284

    
285
        @Override
286
        public FolderDTO createFolder(Long userId, Long parentId, String name)
287
                        throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
288
                // Validate.
289
                if (userId == null)
290
                        throw new ObjectNotFoundException("No user specified");
291
                if (StringUtils.isEmpty(name))
292
                        throw new ObjectNotFoundException("New folder name is empty");
293
                if (parentId == null)
294
                        throw new ObjectNotFoundException("No parent specified");
295
                if (dao.existsFolderOrFile(parentId, name))
296
                        throw new DuplicateNameException("A folder or file with the name '" +
297
                                                name + "' already exists at this level");
298

    
299
                User creator = dao.getEntityById(User.class, userId);
300

    
301
                Folder parent = null;
302
                try {
303
                        parent = dao.getEntityById(Folder.class, parentId);
304
                } catch (ObjectNotFoundException onfe) {
305
                        // Supply a more accurate problem description.
306
                        throw new ObjectNotFoundException("Parent folder not found");
307
                }
308
                if (!parent.hasWritePermission(creator))
309
                        throw new InsufficientPermissionsException("You don't have the permissions" +
310
                                        " to write to this folder");
311

    
312
                // Do the actual work.
313
                return createFolder(name, parent, creator);
314
        }
315

    
316
        /**
317
         * Create a new folder with the provided name, parent and owner.
318
         *
319
         * @param name
320
         * @param parent
321
         * @param creator
322
         * @return the new folder
323
         */
324
        private FolderDTO createFolder(String name, Folder parent, User creator) {
325
                Folder folder = new Folder();
326
                folder.setName(name);
327
                if (parent != null) {
328
                        parent.addSubfolder(folder);
329
                        folder.setOwner(parent.getOwner());
330
                } else
331
                        folder.setOwner(creator);
332

    
333
                Date now = new Date();
334
                AuditInfo auditInfo = new AuditInfo();
335
                auditInfo.setCreatedBy(creator);
336
                auditInfo.setCreationDate(now);
337
                auditInfo.setModifiedBy(creator);
338
                auditInfo.setModificationDate(now);
339
                folder.setAuditInfo(auditInfo);
340
                touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
341

    
342
                if (parent != null)
343
                        for (Permission p : parent.getPermissions()) {
344
                                Permission permission = new Permission();
345
                                permission.setGroup(p.getGroup());
346
                                permission.setUser(p.getUser());
347
                                permission.setRead(p.getRead());
348
                                permission.setWrite(p.getWrite());
349
                                permission.setModifyACL(p.getModifyACL());
350
                                folder.addPermission(permission);
351
                        }
352
                else {
353
                        Permission permission = new Permission();
354
                        permission.setUser(creator);
355
                        permission.setRead(true);
356
                        permission.setWrite(true);
357
                        permission.setModifyACL(true);
358
                        folder.addPermission(permission);
359
                }
360
                dao.create(folder);
361
                return folder.getDTO();
362
        }
363

    
364
        /*
365
         * Deletes the given folder and all its subfolders and files
366
         * Only the permissions for top folder are checked
367
         *
368
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFolder(java.lang.Long,
369
         *      java.lang.Long)
370
         */
371
        public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
372
                // Validate.
373
                if (userId == null)
374
                        throw new ObjectNotFoundException("No user specified");
375
                if (folderId == null)
376
                        throw new ObjectNotFoundException("No folder specified");
377

    
378
                // Do the actual work.
379
                final Folder folder = dao.getEntityById(Folder.class, folderId);
380
                final Folder parent = folder.getParent();
381
                if (parent == null)
382
                        throw new ObjectNotFoundException("Deleting the root folder is not allowed");
383
                final User user = dao.getEntityById(User.class, userId);
384
                if (!folder.hasDeletePermission(user)) {
385
                        logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
386
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
387
                }
388
                removeSubfolderFiles(folder);
389
                parent.removeSubfolder(folder);
390
                dao.delete(folder);
391
                touchParentFolders(parent, user, new Date());
392
        }
393

    
394
        /**
395
         * Traverses the folder and deletes all actual files (file system)
396
         * regardless of permissions
397
         *
398
         * @param folder
399
         */
400
        private void removeSubfolderFiles(Folder folder) {
401
                //remove files for all subfolders
402
                for (Folder subfolder:folder.getSubfolders())
403
                        removeSubfolderFiles(subfolder);
404
                //remove this folder's file bodies (actual files)
405
                for (FileHeader file:folder.getFiles()) {
406
                        for (FileBody body:file.getBodies())
407
                                deleteActualFile(body.getStoredFilePath());
408
                        indexFile(file.getId(), true);
409
                }
410
        }
411

    
412
        @SuppressWarnings("unchecked")
413
        public List<FolderDTO> getSubfolders(Long userId, Long folderId)
414
                        throws ObjectNotFoundException, InsufficientPermissionsException {
415
                if (userId == null)
416
                        throw new ObjectNotFoundException("No user specified");
417
                if (folderId == null)
418
                        throw new ObjectNotFoundException("No folder specified");
419
                User user = dao.getEntityById(User.class, userId);
420
                Folder folder = dao.getEntityById(Folder.class, folderId);
421
                if (!folder.hasReadPermission(user))
422
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
423
                List<FolderDTO> result = new ArrayList<FolderDTO>();
424
                if (folder.hasReadPermission(user))
425
                        for (Folder f : folder.getSubfolders())
426
                                if (f.hasReadPermission(user) && !f.isDeleted())
427
                                        result.add(f.getDTO());
428
                return result;
429
        }
430

    
431
        @Override
432
        public FolderDTO updateFolder(Long userId, Long folderId, String folderName,
433
                                Set<PermissionDTO> permissions)
434
                        throws InsufficientPermissionsException, ObjectNotFoundException,
435
                        DuplicateNameException {
436

    
437
                // Validate.
438
                if (userId == null)
439
                        throw new ObjectNotFoundException("No user specified");
440
                if (folderId == null)
441
                        throw new ObjectNotFoundException("No folder specified");
442

    
443
                Folder folder = dao.getEntityById(Folder.class, folderId);
444
                User user = dao.getEntityById(User.class, userId);
445
                if (folderName != null && !folder.hasWritePermission(user))
446
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
447
                if(permissions != null && !permissions.isEmpty() && !folder.hasModifyACLPermission(user))
448
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
449

    
450
                Folder parent = folder.getParent();
451
                if (folderName != null) {
452
                        if (parent != null)
453
                                if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
454
                                        throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
455

    
456
                        // Do the actual modification.
457
                        folder.setName(folderName);
458
                }
459
                if (permissions != null)
460
                        setFolderPermissions(user, folder, permissions);
461

    
462
                folder.getAuditInfo().setModificationDate(new Date());
463
                folder.getAuditInfo().setModifiedBy(user);
464
                dao.update(folder);
465
                touchParentFolders(folder, user, new Date());
466
                return folder.getDTO();
467
        }
468

    
469
        /*
470
         * (non-Javadoc)
471
         *
472
         * @see gr.ebs.gss.server.ejb.ExternalAPI#createGroup(java.lang.Long,
473
         *      java.lang.String)
474
         */
475
        public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
476
                // Validate.
477
                if (userId == null)
478
                        throw new ObjectNotFoundException("No user specified");
479
                if (StringUtils.isEmpty(name))
480
                        throw new ObjectNotFoundException("New group name is empty");
481
                if (name.indexOf('/')>=0)
482
                        throw new IllegalArgumentException("Character '/' is not allowed in group name");
483
                if (dao.existsGroup(userId, name))
484
                        throw new DuplicateNameException("A group with the name '" + name + "' already exists");
485

    
486
                // TODO: Check permissions
487

    
488
                final User owner = dao.getEntityById(User.class, userId);
489

    
490
                // Do the actual work.
491
                owner.createGroup(name);
492
        }
493

    
494
        /*
495
         * (non-Javadoc)
496
         *
497
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteGroup(java.lang.Long,
498
         *      java.lang.Long)
499
         */
500
        public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
501
                // Validate.
502
                if (userId == null)
503
                        throw new ObjectNotFoundException("No user specified");
504
                if (groupId == null)
505
                        throw new ObjectNotFoundException("No group specified");
506

    
507
                // Do the actual work.
508
                final User owner = dao.getEntityById(User.class, userId);
509
                final Group group = dao.getEntityById(Group.class, groupId);
510
                // Only delete the group if actually owned by the user.
511
                if (group.getOwner().equals(owner)) {
512
                        List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
513
                        for (Folder f : folders){
514
                                f.getPermissions().removeAll(group.getPermissions());
515
                                for(FileHeader file : f.getFiles())
516
                                        file.getPermissions().removeAll(group.getPermissions());
517
                        }
518
                        List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
519
                        for(FileHeader h : files)
520
                                h.getPermissions().removeAll(group.getPermissions());
521
                        owner.removeSpecifiedGroup(group);
522
                        dao.delete(group);
523
                }
524
                else throw new InsufficientPermissionsException("You are not the owner of this group");
525
        }
526

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

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

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

    
582

    
583

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

    
609
        /*
610
         * (non-Javadoc)
611
         *
612
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFile(java.lang.Long,
613
         *      java.lang.Long)
614
         */
615
        public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
616
                // Validate.
617
                if (userId == null)
618
                        throw new ObjectNotFoundException("No user specified");
619
                if (fileId == null)
620
                        throw new ObjectNotFoundException("No file specified");
621

    
622
                // Do the actual work.
623
                final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
624
                final Folder parent = file.getFolder();
625
                if (parent == null)
626
                        throw new ObjectNotFoundException("The specified file has no parent folder");
627
                final User user = dao.getEntityById(User.class, userId);
628
                if (!file.hasDeletePermission(user))
629
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
630
                for (final FileBody body : file.getBodies())
631
                        deleteActualFile(body.getStoredFilePath());
632
                dao.delete(file);
633
                touchParentFolders(parent, user, new Date());
634
                indexFile(fileId, true);
635
        }
636

    
637
        private void deleteActualFile(String filePath) {
638
                if (filePath == null)
639
                        return;
640
                File file = new File(filePath);
641
                if (!file.delete())
642
                        logger.error("Could not delete file " + filePath);
643
        }
644

    
645
        public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
646
                if (userId == null)
647
                        throw new ObjectNotFoundException("No user specified");
648
                if (fileHeaderId == null)
649
                        throw new ObjectNotFoundException("No file specified");
650
                if (StringUtils.isEmpty(tag))
651
                        throw new ObjectNotFoundException("Tag is empty");
652

    
653
                final User user = dao.getEntityById(User.class, userId);
654
                final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
655
                final Folder parent = fh.getFolder();
656
                if (parent == null)
657
                        throw new ObjectNotFoundException("The specified file has no parent folder");
658
                user.addTag(fh, tag);
659
                touchParentFolders(parent, user, new Date());
660
        }
661

    
662
        public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
663
                return dao.getUserTags(userId);
664
        }
665

    
666
        public void updateFile(Long userId, Long fileId, String name,
667
                                String tagSet, Date modificationDate, Boolean versioned,
668
                                Boolean readForAll,        Set<PermissionDTO> permissions)
669
                        throws DuplicateNameException, ObjectNotFoundException,        InsufficientPermissionsException {
670
                if (userId == null)
671
                        throw new ObjectNotFoundException("No user specified");
672
                if (fileId == null)
673
                        throw new ObjectNotFoundException("No file specified");
674
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
675
                final Folder parent = file.getFolder();
676
                if (parent == null)
677
                        throw new ObjectNotFoundException("The specified file has no parent folder");
678

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

    
690
                if (name != null) {
691
                        // Do plain check for file already exists.
692
                        // Extreme concurrency case should be caught by constraint violation later.
693
                        if (dao.existsFolderOrFile(parent.getId(), name)) throw new DuplicateNameException("A file or folder with the name '" + name + "' already exists");
694
                        file.setName(name);
695
                }
696

    
697
                if (modificationDate != null)
698
                        file.getAuditInfo().setModificationDate(modificationDate);
699
                else
700
                        file.getAuditInfo().setModificationDate(new Date());
701
                file.getAuditInfo().setModifiedBy(user);
702

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

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

    
743
                touchParentFolders(parent, user, new Date());
744

    
745
                // Re-index the file if it was modified.
746
                if (name != null || tagSet != null)
747
                        indexFile(fileId, false);
748
        }
749

    
750
        @Override
751
        public InputStream getFileContents(Long userId, Long fileId)
752
                        throws ObjectNotFoundException, InsufficientPermissionsException {
753
                if (userId == null)
754
                        throw new ObjectNotFoundException("No user specified");
755
                if (fileId == null)
756
                        throw new ObjectNotFoundException("No file specified");
757

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

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

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

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

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

    
802
        /* (non-Javadoc)
803
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFile(java.lang.Long, java.lang.Long)
804
         */
805
        public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
806
                if (userId == null)
807
                        throw new ObjectNotFoundException("No user specified");
808
                if (fileId == null)
809
                        throw new ObjectNotFoundException("No file specified");
810
                final User user = dao.getEntityById(User.class, userId);
811
                final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
812
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
813
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
814
                return file.getDTO();
815
        }
816

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

    
831
        @Override
832
        public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
833
                        throws ObjectNotFoundException {
834
                if (ownerId == null)
835
                        throw new ObjectNotFoundException("No user specified");
836
                if (StringUtils.isEmpty(path))
837
                        throw new ObjectNotFoundException("No path specified");
838

    
839
                User owner = dao.getEntityById(User.class, ownerId);
840
                List<String> pathElements = new ArrayList<String>();
841
                StringTokenizer st = new StringTokenizer(path, "/");
842
                while (st.hasMoreTokens())
843
                        pathElements.add(st.nextToken());
844
                if (pathElements.size() < 1)
845
                        return getRootFolder(owner.getId());
846
                // Store the last element, since it requires special handling.
847
                String lastElement = pathElements.remove(pathElements.size() - 1);
848
                FolderDTO cursor = getRootFolder(owner.getId());
849
                // Traverse and verify the specified folder path.
850
                for (String pathElement : pathElements) {
851
                        cursor = getFolder(cursor.getId(), pathElement);
852
                        if (cursor.isDeleted())
853
                                throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
854
                }
855

    
856
                // Use the lastElement to retrieve the actual resource.
857
                Object resource = null;
858
                try {
859
                        FileHeaderDTO file = getFile(cursor.getId(), lastElement);
860
                        if (ignoreDeleted && file.isDeleted())
861
                                throw new ObjectNotFoundException("Resource not found");
862
                        resource = file;
863
                } catch (ObjectNotFoundException e) {
864
                        // Perhaps the requested resource is not a file, so
865
                        // check for folders as well.
866
                        FolderDTO folder = getFolder(cursor.getId(), lastElement);
867
                        if (ignoreDeleted && folder.isDeleted())
868
                                throw new ObjectNotFoundException("Resource not found");
869
                        resource = folder;
870
                }
871
                return resource;
872
        }
873

    
874
        /**
875
         * Retrieve a file for the specified user that has the specified name and
876
         * its parent folder has id equal to folderId.
877
         *
878
         * @param userId the ID of the current user
879
         * @param folderId the ID of the parent folder
880
         * @param name the name of the requested file
881
         * @return the file found
882
         * @throws ObjectNotFoundException if the specified folder or file was not
883
         *             found, with the exception message mentioning the precise
884
         *             problem
885
         */
886
        private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
887
                if (folderId == null)
888
                        throw new ObjectNotFoundException("No parent folder specified");
889
                if (StringUtils.isEmpty(name))
890
                        throw new ObjectNotFoundException("No file specified");
891

    
892
                FileHeader file = dao.getFile(folderId, name);
893
                return file.getDTO();
894
        }
895

    
896
        /**
897
         * Retrieve a folder for the specified user that has the specified name and
898
         * its parent folder has id equal to parentId.
899
         *
900
         * @param parentId the ID of the parent folder
901
         * @param name the name of the requested folder
902
         * @return the folder found
903
         * @throws ObjectNotFoundException if the specified folder or parent was not
904
         *             found, with the exception message mentioning the precise
905
         *             problem
906
         */
907
        private FolderDTO getFolder(Long parentId, String name) throws ObjectNotFoundException {
908
                if (parentId == null)
909
                        throw new ObjectNotFoundException("No parent folder specified");
910
                if (StringUtils.isEmpty(name))
911
                        throw new ObjectNotFoundException("No folder specified");
912

    
913
                Folder folder = dao.getFolder(parentId, name);
914
                return folder.getDTO();
915
        }
916

    
917
        private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
918
                File file = null;
919
                try {
920
                        file = uploadFile(resourceInputStream, userId);
921
                } catch ( IOException ioe) {
922
                        // Supply a more accurate problem description.
923
                        throw new GSSIOException("Problem creating file",ioe);
924
                }
925
                return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
926
        }
927

    
928
        @Override
929
        public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
930
                if (userId == null)
931
                        throw new ObjectNotFoundException("No user specified");
932
                if (fileId == null)
933
                        throw new ObjectNotFoundException("No file specified");
934
                if (StringUtils.isEmpty(dest))
935
                        throw new ObjectNotFoundException("No destination specified");
936

    
937
                Object destination = getResourceAtPath(userId, getParentPath(dest), true);
938
                if (!(destination instanceof FolderDTO))
939
                        throw new ObjectNotFoundException("Destination parent folder not found");
940
                FolderDTO parent = (FolderDTO) destination;
941
                copyFile(userId, fileId, parent.getId(), getLastElement(dest));
942
        }
943

    
944
        @Override
945
        public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
946
                if (userId == null)
947
                        throw new ObjectNotFoundException("No user specified");
948
                if (ownerId == null)
949
                        throw new ObjectNotFoundException("No owner specified");
950
                if (fileId == null)
951
                        throw new ObjectNotFoundException("No file specified");
952
                if (StringUtils.isEmpty(dest))
953
                        throw new ObjectNotFoundException("No destination specified");
954

    
955
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
956
                if (!(destination instanceof FolderDTO))
957
                        throw new ObjectNotFoundException("Destination parent folder not found");
958
                FolderDTO parent = (FolderDTO) destination;
959
                copyFile(userId, fileId, parent.getId(), getLastElement(dest));
960
        }
961

    
962
        @Override
963
        public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
964
                if (userId == null)
965
                        throw new ObjectNotFoundException("No user specified");
966
                if (fileId == null)
967
                        throw new ObjectNotFoundException("No file specified");
968
                if (destId == null)
969
                        throw new ObjectNotFoundException("No destination specified");
970
                if (StringUtils.isEmpty(destName))
971
                        throw new ObjectNotFoundException("No destination file name specified");
972

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

    
999
                } catch (FileNotFoundException e) {
1000
                        throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
1001
                }
1002

    
1003
        }
1004

    
1005
        @Override
1006
        public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1007
                if (userId == null)
1008
                        throw new ObjectNotFoundException("No user specified");
1009
                if (folderId == null)
1010
                        throw new ObjectNotFoundException("No folder specified");
1011
                if (StringUtils.isEmpty(dest))
1012
                        throw new ObjectNotFoundException("No destination specified");
1013

    
1014
                Object destination = getResourceAtPath(userId, getParentPath(dest), true);
1015
                if (!(destination instanceof FolderDTO))
1016
                        throw new ObjectNotFoundException("Destination folder not found");
1017
                FolderDTO parent = (FolderDTO) destination;
1018
                copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
1019
        }
1020

    
1021
        @Override
1022
        public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1023
                if (userId == null)
1024
                        throw new ObjectNotFoundException("No user specified");
1025
                if (folderId == null)
1026
                        throw new ObjectNotFoundException("No folder specified");
1027
                if (destId == null)
1028
                        throw new ObjectNotFoundException("No destination specified");
1029
                if (StringUtils.isEmpty(destName))
1030
                        throw new ObjectNotFoundException("No destination folder name specified");
1031
                Folder folder = dao.getEntityById(Folder.class, folderId);
1032
                Folder destination = dao.getEntityById(Folder.class, destId);
1033
                User user = dao.getEntityById(User.class, userId);
1034
                if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1035
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1036
                createFolder(user.getId(), destination.getId(), destName);
1037
        }
1038

    
1039
        @Override
1040
        public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1041
                if (userId == null)
1042
                        throw new ObjectNotFoundException("No user specified");
1043
                if (ownerId == null)
1044
                        throw new ObjectNotFoundException("No owner specified");
1045
                if (folderId == null)
1046
                        throw new ObjectNotFoundException("No folder specified");
1047
                if (StringUtils.isEmpty(dest))
1048
                        throw new ObjectNotFoundException("No destination specified");
1049

    
1050
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1051
                if (!(destination instanceof FolderDTO))
1052
                        throw new ObjectNotFoundException("Destination folder not found");
1053
                FolderDTO parent = (FolderDTO) destination;
1054
                copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
1055
        }
1056

    
1057
        @Override
1058
        public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1059
                if (userId == null)
1060
                        throw new ObjectNotFoundException("No user specified");
1061
                if (folderId == null)
1062
                        throw new ObjectNotFoundException("No folder specified");
1063
                if (destId == null)
1064
                        throw new ObjectNotFoundException("No destination specified");
1065
                if (StringUtils.isEmpty(destName))
1066
                        throw new ObjectNotFoundException("No destination folder name specified");
1067

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

    
1092
        }
1093

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

    
1120
        /**
1121
         * Get the last element in a path that denotes the file or folder name.
1122
         *
1123
         * @param path the provided path
1124
         * @return the last element in the path
1125
         */
1126
        private String getLastElement(String path) {
1127
                int lastDelimiter = path.lastIndexOf('/');
1128
                if (lastDelimiter == -1)
1129
                        // No path found.
1130
                        return path;
1131
                else if (lastDelimiter < path.length() - 1)
1132
                        // Return the part after the delimiter.
1133
                        return path.substring(lastDelimiter + 1);
1134
                else {
1135
                        // Remove the trailing delimiter and then recurse.
1136
                        String strippedTrail = path.substring(0, lastDelimiter);
1137
                        return getLastElement(strippedTrail);
1138
                }
1139
        }
1140

    
1141
        @Override
1142
        public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1143
                if (userId == null)
1144
                        throw new ObjectNotFoundException("No user specified");
1145
                if (fileId == null)
1146
                        throw new ObjectNotFoundException("No file specified");
1147

    
1148
                // Do the actual work.
1149
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1150
                Folder parent = file.getFolder();
1151
                if (parent == null)
1152
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1153
                User user = dao.getEntityById(User.class, userId);
1154
                if (!file.hasDeletePermission(user))
1155
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1156

    
1157
                file.setDeleted(true);
1158
                dao.update(file);
1159
                touchParentFolders(parent, user, new Date());
1160
        }
1161

    
1162
        @Override
1163
        public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1164
                if (userId == null)
1165
                        throw new ObjectNotFoundException("No user specified");
1166
                if (ownerId == null)
1167
                        throw new ObjectNotFoundException("No owner specified");
1168
                if (fileId == null)
1169
                        throw new ObjectNotFoundException("No file specified");
1170
                if (StringUtils.isEmpty(dest))
1171
                        throw new ObjectNotFoundException("No destination specified");
1172

    
1173
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1174
                if (!(destination instanceof FolderDTO))
1175
                        throw new ObjectNotFoundException("Destination parent folder not found");
1176
                FolderDTO parent = (FolderDTO) destination;
1177
                moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1178
        }
1179

    
1180
        @Override
1181
        public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1182
                if (userId == null)
1183
                        throw new ObjectNotFoundException("No user specified");
1184
                if (fileId == null)
1185
                        throw new ObjectNotFoundException("No file specified");
1186
                if (destId == null)
1187
                        throw new ObjectNotFoundException("No destination specified");
1188
                if (StringUtils.isEmpty(destName))
1189
                        throw new ObjectNotFoundException("No destination file name specified");
1190

    
1191
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1192
                Folder source = file.getFolder();
1193
                Folder destination = dao.getEntityById(Folder.class, destId);
1194

    
1195
                User owner = dao.getEntityById(User.class, userId);
1196
                if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1197
                        throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1198

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

    
1230
        @Override
1231
        public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1232
                if (userId == null)
1233
                        throw new ObjectNotFoundException("No user specified");
1234
                if (ownerId == null)
1235
                        throw new ObjectNotFoundException("No owner specified");
1236
                if (folderId == null)
1237
                        throw new ObjectNotFoundException("No folder specified");
1238
                if (StringUtils.isEmpty(dest))
1239
                        throw new ObjectNotFoundException("No destination specified");
1240

    
1241
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1242
                if (!(destination instanceof FolderDTO))
1243
                        throw new ObjectNotFoundException("Destination parent folder not found");
1244
                FolderDTO parent = (FolderDTO) destination;
1245
                moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1246
        }
1247

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

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

    
1304
        @Override
1305
        public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1306
                // Validate.
1307
                if (userId == null)
1308
                        throw new ObjectNotFoundException("No user specified");
1309

    
1310
                // Do the actual work.
1311
                final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1312
                final List<FileHeader> files = dao.getDeletedFiles(userId);
1313
                for (final FileHeader f : files)
1314
                        result.add(f.getDTO());
1315
                return result;
1316
        }
1317

    
1318
        @Override
1319
        public void removeFileFromTrash(Long userId, Long fileId)
1320
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1321
                if (userId == null)
1322
                        throw new ObjectNotFoundException("No user specified");
1323
                if (fileId == null)
1324
                        throw new ObjectNotFoundException("No file specified");
1325

    
1326
                // Do the actual work.
1327
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1328
                Folder parent = file.getFolder();
1329
                if (parent == null)
1330
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1331
                User user = dao.getEntityById(User.class, userId);
1332
                if (!file.hasDeletePermission(user))
1333
                        throw new InsufficientPermissionsException("User " + user.getUsername() +
1334
                                                " cannot restore file " + file.getName());
1335

    
1336
                file.setDeleted(false);
1337
                dao.update(file);
1338
                touchParentFolders(parent, user, new Date());
1339
        }
1340

    
1341
        @Override
1342
        public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1343
                if (userId == null)
1344
                        throw new ObjectNotFoundException("No user specified");
1345
                if (folderId == null)
1346
                        throw new ObjectNotFoundException("No folder specified");
1347
                Folder folder = dao.getEntityById(Folder.class, folderId);
1348
                User user = dao.getEntityById(User.class, userId);
1349
                if (!folder.hasDeletePermission(user))
1350
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1351
                folder.setDeleted(true);
1352
                dao.update(folder);
1353
                touchParentFolders(folder, user, new Date());
1354
                for (FileHeader file : folder.getFiles())
1355
                        moveFileToTrash(userId, file.getId());
1356
                for (Folder subFolder : folder.getSubfolders())
1357
                        moveFolderToTrash(userId, subFolder.getId());
1358

    
1359
        }
1360

    
1361
        @Override
1362
        public void removeFolderFromTrash(Long userId, Long folderId)
1363
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1364
                if (userId == null)
1365
                        throw new ObjectNotFoundException("No user specified");
1366
                if (folderId == null)
1367
                        throw new ObjectNotFoundException("No folder specified");
1368
                Folder folder = dao.getEntityById(Folder.class, folderId);
1369
                User user = dao.getEntityById(User.class, userId);
1370
                if (!folder.hasDeletePermission(user))
1371
                        throw new InsufficientPermissionsException("User " + user.getUsername() +
1372
                                                " cannot restore folder " + folder.getName());
1373
                folder.setDeleted(false);
1374
                for (FileHeader file : folder.getFiles())
1375
                        removeFileFromTrash(userId, file.getId());
1376
                for (Folder subFolder : folder.getSubfolders())
1377
                        removeFolderFromTrash(userId, subFolder.getId());
1378
                dao.update(folder);
1379
                touchParentFolders(folder, user, new Date());
1380
        }
1381

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

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

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

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

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

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

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

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

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

    
1466
        /* (non-Javadoc)
1467
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolderPermissions(java.lang.Long, java.lang.Long)
1468
         */
1469
        @Override
1470
        public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1471
                if (userId == null)
1472
                        throw new ObjectNotFoundException("No user specified");
1473
                if (folderId == null)
1474
                        throw new ObjectNotFoundException("No folder specified");
1475
                User user = dao.getEntityById(User.class, userId);
1476
                Folder folder = dao.getEntityById(Folder.class, folderId);
1477
                if(!folder.hasReadPermission(user))
1478
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1479
                Set<Permission> perms = folder.getPermissions();
1480
                Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1481
                for (Permission perm : perms)
1482
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1483
                                result.add(perm.getDTO());
1484
                for (Permission perm : perms)
1485
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1486
                        } else
1487
                                result.add(perm.getDTO());
1488
                return result;
1489

    
1490
        }
1491

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

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

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

    
1551
        }
1552

    
1553
        /* (non-Javadoc)
1554
         * @see gr.ebs.gss.server.ejb.ExternalAPI#addUserToGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1555
         */
1556
        @Override
1557
        public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1558
                if (userId == null)
1559
                        throw new ObjectNotFoundException("No user specified");
1560
                if (groupId == null)
1561
                        throw new ObjectNotFoundException("No group specified");
1562
                if (userToAddId == null)
1563
                        throw new ObjectNotFoundException("No user to add specified");
1564
                User user = dao.getEntityById(User.class, userId);
1565
                Group group = dao.getEntityById(Group.class, groupId);
1566
                if (!group.getOwner().equals(user))
1567
                        throw new InsufficientPermissionsException();
1568
                User userToAdd = dao.getEntityById(User.class, userToAddId);
1569
                if (group.contains(userToAdd))
1570
                        throw new DuplicateNameException("User already exists in group");
1571
                group.getMembers().add(userToAdd);
1572
                dao.update(group);
1573

    
1574
        }
1575

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

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

    
1599
        /* (non-Javadoc)
1600
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeMemberFromGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1601
         */
1602
        @Override
1603
        public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1604
                if (userId == null)
1605
                        throw new ObjectNotFoundException("No user specified");
1606
                if (groupId == null)
1607
                        throw new ObjectNotFoundException("No group specified");
1608
                if (memberId == null)
1609
                        throw new ObjectNotFoundException("No member specified");
1610
                User owner = dao.getEntityById(User.class, userId);
1611
                Group group = dao.getEntityById(Group.class, groupId);
1612
                User member = dao.getEntityById(User.class, memberId);
1613
                if (!group.getOwner().equals(owner))
1614
                        throw new InsufficientPermissionsException("User is not the owner of the group");
1615
                group.removeMemberFromGroup(member);
1616
                dao.update(group);
1617

    
1618
        }
1619

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

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

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

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

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

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

    
1717
        /* (non-Javadoc)
1718
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getSharedFiles(java.lang.Long, java.lang.Long)
1719
         */
1720
        @Override
1721
        public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1722
                if (ownerId == null)
1723
                        throw new ObjectNotFoundException("No owner specified");
1724
                if (callingUserId == null)
1725
                        throw new ObjectNotFoundException("No calling user specified");
1726
                List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1727
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1728
                for (FileHeader f : folders)
1729
                        result.add(f.getDTO());
1730
                return result;
1731
        }
1732

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

    
1748
        }
1749

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

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

    
1786
        }
1787

    
1788
        /* (non-Javadoc)
1789
         * @see gr.ebs.gss.server.ejb.ExternalAPI#searchFiles(java.lang.Long, java.lang.String)
1790
         */
1791
        @Override
1792
        public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1793
                if (userId == null)
1794
                        throw new ObjectNotFoundException("No user specified");
1795
                User user = getUser(userId);
1796
                if (query == null)
1797
                        throw new ObjectNotFoundException("No query specified");
1798
                List<FileHeader> files = search(user.getId(), query);
1799
                List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1800
                for(FileHeader f : files)
1801
                        res.add(f.getDTO());
1802
                return res;
1803
        }
1804

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

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

    
1844
                        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1845
                        DocumentBuilder db = dbf.newDocumentBuilder();
1846
                        Document doc = db.parse(method.getResponseBodyAsStream());
1847
                        method.releaseConnection();
1848

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

    
1894
        /* (non-Javadoc)
1895
         * @see gr.ebs.gss.server.ejb.ExternalAPI#copyFiles(java.lang.Long, java.util.List, java.lang.Long)
1896
         */
1897
        @Override
1898
        public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1899
                for(Long l : fileIds){
1900
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1901
                        copyFile(userId, l, destId, file.getName());
1902
                }
1903

    
1904

    
1905
        }
1906

    
1907
        /* (non-Javadoc)
1908
         * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFiles(java.lang.Long, java.util.List, java.lang.Long)
1909
         */
1910
        @Override
1911
        public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1912
                for(Long l : fileIds){
1913
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1914
                        moveFile(userId, l, destId, file.getName());
1915
                }
1916

    
1917
        }
1918

    
1919
        /* (non-Javadoc)
1920
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFiles(java.lang.Long, java.util.List)
1921
         */
1922
        @Override
1923
        public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1924
                if (userId == null)
1925
                        throw new ObjectNotFoundException("No user specified");
1926
                final User user = dao.getEntityById(User.class, userId);
1927
                List<String> filesToRemove = new ArrayList<String>();
1928
                //first delete database objects
1929
                for(Long fileId : fileIds){
1930
                        if (fileId == null)
1931
                                throw new ObjectNotFoundException("No file specified");
1932
                        final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1933
                        final Folder parent = file.getFolder();
1934
                        if (parent == null)
1935
                                throw new ObjectNotFoundException("The specified file has no parent folder");
1936
                        if (!file.hasDeletePermission(user))
1937
                                throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1938

    
1939
                        parent.removeFile(file);
1940
                        for (final FileBody body : file.getBodies())
1941
                                filesToRemove.add(body.getStoredFilePath());
1942
                        dao.delete(file);
1943
                        touchParentFolders(parent, user, new Date());
1944
                }
1945
                //then remove physical files if everything is ok
1946
                for(String physicalFileName : filesToRemove)
1947
                        deleteActualFile(physicalFileName);
1948
                //then unindex deleted files
1949
                for(Long fileId : fileIds)
1950
                        indexFile(fileId, true);
1951

    
1952
        }
1953

    
1954
        /* (non-Javadoc)
1955
         * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFilesToTrash(java.lang.Long, java.util.List)
1956
         */
1957
        @Override
1958
        public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1959
                for(Long l : fileIds)
1960
                        moveFileToTrash(userId, l);
1961

    
1962
        }
1963

    
1964
        @Override
1965
        public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1966
                for(Long l : fileIds)
1967
                        removeFileFromTrash(userId, l);
1968

    
1969
        }
1970

    
1971
        @Override
1972
        public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1973
                if (userId == null)
1974
                        throw new ObjectNotFoundException("No user specified");
1975
                User user = dao.getEntityById(User.class, userId);
1976
                Nonce nonce = Nonce.createNonce(user.getId());
1977
                dao.create(nonce);
1978
                return nonce;
1979
        }
1980

    
1981
        @Override
1982
        public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1983
                if (userId == null)
1984
                        throw new ObjectNotFoundException("No user specified");
1985
                if (nonce == null)
1986
                        throw new ObjectNotFoundException("No nonce specified");
1987
                return dao.getNonce(nonce, userId);
1988
        }
1989

    
1990
        @Override
1991
        public void removeNonce(Long id) throws ObjectNotFoundException {
1992
                if (id == null)
1993
                        throw new ObjectNotFoundException("No nonce specified");
1994
                Nonce nonce = dao.getEntityById(Nonce.class, id);
1995
                dao.delete(nonce);
1996
        }
1997

    
1998
        @Override
1999
        public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
2000
                if (userId == null)
2001
                        throw new ObjectNotFoundException("No user specified");
2002
                User user = dao.getEntityById(User.class, userId);
2003
                user.setNonce(nonce);
2004
                user.setNonceExpiryDate(nonceExpiryDate);
2005
        }
2006

    
2007
        /* (non-Javadoc)
2008
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserStatistics(java.lang.Long)
2009
         */
2010
        @Override
2011
        public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
2012
                if (userId == null)
2013
                        throw new ObjectNotFoundException("No user specified");
2014
                StatsDTO stats = new StatsDTO();
2015
                stats.setFileCount(dao.getFileCount(userId));
2016
                Long fileSize = dao.getFileSize(userId);
2017
                stats.setFileSize(fileSize);
2018
                Long quota = getQuota(userId);
2019
                Long quotaLeft = quota - fileSize;
2020
                stats.setQuotaLeftSize(quotaLeft);
2021
                return stats;
2022
        }
2023

    
2024
        /* (non-Javadoc)
2025
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getVersions(java.lang.Long, java.lang.Long)
2026
         */
2027
        @Override
2028
        public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2029
                if (userId == null)
2030
                        throw new ObjectNotFoundException("No user specified");
2031
                if (fileId == null)
2032
                        throw new ObjectNotFoundException("No file specified");
2033
                User user = dao.getEntityById(User.class, userId);
2034
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2035
                if(!header.hasReadPermission(user))
2036
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2037
                List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
2038
                for(int i = header.getBodies().size()-1 ; i>=0; i--)
2039
                        result.add(header.getBodies().get(i).getDTO());
2040
                return result;
2041
        }
2042

    
2043
        /* (non-Javadoc)
2044
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeVersion(java.lang.Long, java.lang.Long, java.lang.Long)
2045
         */
2046
        @Override
2047
        public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
2048
                if (userId == null)
2049
                        throw new ObjectNotFoundException("No user specified");
2050
                if (fileId == null)
2051
                        throw new ObjectNotFoundException("No file specified");
2052
                if (bodyId == null)
2053
                        throw new ObjectNotFoundException("No body specified");
2054
                User user = dao.getEntityById(User.class, userId);
2055
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2056
                if(!header.hasWritePermission(user))
2057
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2058
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
2059
                if(body.equals(header.getCurrentBody())){
2060

    
2061
                        if(header.getBodies().size() == 1)
2062
                                throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
2063
                        for(FileBody b : header.getBodies())
2064
                                if(b.getVersion() == body.getVersion()-1)
2065
                                        header.setCurrentBody(b);
2066
                }
2067
                deleteActualFile(body.getStoredFilePath());
2068
                header.getBodies().remove(body);
2069

    
2070
                Folder parent = header.getFolder();
2071
                touchParentFolders(parent, user, new Date());
2072

    
2073
        }
2074

    
2075
        @Override
2076
        public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException,  GSSIOException, QuotaExceededException {
2077
                if (userId == null)
2078
                        throw new ObjectNotFoundException("No user specified");
2079
                if (fileId == null)
2080
                        throw new ObjectNotFoundException("No file specified");
2081
                User user = dao.getEntityById(User.class, userId);
2082
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2083
                if(!header.hasWritePermission(user))
2084
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2085
                FileBody body = dao.getFileVersion(fileId, version);
2086
                final File fileContents = new File(body.getStoredFilePath());
2087

    
2088
                try {
2089
                        updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
2090
                } catch (FileNotFoundException e) {
2091
                        throw new GSSIOException(e);
2092
                }
2093

    
2094
        }
2095

    
2096
        /* (non-Javadoc)
2097
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
2098
         */
2099
        @Override
2100
        public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
2101
                if (userId == null)
2102
                        throw new ObjectNotFoundException("No user specified");
2103
                if (fileId == null)
2104
                        throw new ObjectNotFoundException("No file specified");
2105
                User user = dao.getEntityById(User.class, userId);
2106
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2107
                if(!header.hasWritePermission(user))
2108
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2109
                Iterator<FileBody> it = header.getBodies().iterator();
2110
                while(it.hasNext()){
2111
                        FileBody body = it.next();
2112
                        if(!body.equals(header.getCurrentBody())){
2113
                                deleteActualFile(body.getStoredFilePath());
2114
                                it.remove();
2115
                                dao.delete(body);
2116
                        }
2117
                }
2118
                header.getCurrentBody().setVersion(1);
2119

    
2120
                Folder parent = header.getFolder();
2121
                touchParentFolders(parent, user, new Date());
2122
        }
2123

    
2124
        /**
2125
         * Gets the quota left for specified userId
2126
         * @param userId
2127
         * @return
2128
         */
2129
        private Long getQuotaLeft(Long userId){
2130
                Long fileSize = dao.getFileSize(userId);
2131
                Long quota = getQuota(userId);
2132
                return quota - fileSize;
2133
        }
2134

    
2135
        /**
2136
         * Gets the quota for specified userId
2137
         * @param userId
2138
         * @return
2139
         */
2140
        private Long getQuota(@SuppressWarnings("unused") Long userId){
2141
                Long quota = getConfiguration().getLong("quota", new Long(52428800L));
2142
                return quota;
2143
        }
2144

    
2145
        public void rebuildSolrIndex() {
2146
                MessageProducer sender = null;
2147
                Session session = null;
2148
                Connection qConn = null;
2149
                try {
2150
                        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2151
                        DocumentBuilder db = dbf.newDocumentBuilder();
2152
                        Document doc = db.newDocument();
2153
                        Node root = doc.createElement("delete");
2154
                        doc.appendChild(root);
2155
                        Node queryNode = doc.createElement("query");
2156
                        root.appendChild(queryNode);
2157
                        queryNode.appendChild(doc.createTextNode("*:*"));
2158

    
2159
                        TransformerFactory fact = TransformerFactory.newInstance();
2160
                        Transformer trans = fact.newTransformer();
2161
                        trans.setOutputProperty(OutputKeys.INDENT, "yes");
2162
                        StringWriter sw = new StringWriter();
2163
                        StreamResult sr = new StreamResult(sw);
2164
                        DOMSource source = new DOMSource(doc);
2165
                        trans.transform(source, sr);
2166
                        logger.debug(sw.toString());
2167

    
2168
                        HttpClient httpClient = new HttpClient();
2169
                        PostMethod method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2170
                        method.setRequestEntity(new StringRequestEntity(sw.toString()));
2171
                        int retryCount = 0;
2172
                        int statusCode = 0;
2173
                        String response = null;
2174
                        do {
2175
                                statusCode = httpClient.executeMethod(method);
2176
                                logger.debug("HTTP status: " + statusCode);
2177
                                response = method.getResponseBodyAsString();
2178
                                logger.debug(response);
2179
                                retryCount++;
2180
                                if (statusCode != 200 && retryCount < 3)
2181
                                        try {
2182
                                                Thread.sleep(10000); //Give Solr a little time to be available
2183
                                        } catch (InterruptedException e) {
2184
                                        }
2185
                        } while (statusCode != 200 && retryCount < 3);
2186
                        method.releaseConnection();
2187
                        if (statusCode != 200)
2188
                                throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response);
2189
                        List<Long> fileIds = dao.getAllFileIds();
2190

    
2191
                        Context jndiCtx = new InitialContext();
2192
                        ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
2193
                        Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
2194
                        qConn = factory.createConnection();
2195
                        session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
2196
                        sender = session.createProducer(queue);
2197

    
2198
                        for (Long id : fileIds) {
2199
                                MapMessage map = session.createMapMessage();
2200
                                map.setObject("id", id);
2201
                                map.setBoolean("delete", false);
2202
                                sender.send(map);
2203
                        }
2204
                        sendOptimize(httpClient, 0);
2205
                } catch (DOMException e) {
2206
                        throw new EJBException(e);
2207
                } catch (TransformerConfigurationException e) {
2208
                        throw new EJBException(e);
2209
                } catch (IllegalArgumentException e) {
2210
                        throw new EJBException(e);
2211
                } catch (HttpException e) {
2212
                        throw new EJBException(e);
2213
                } catch (UnsupportedEncodingException e) {
2214
                        throw new EJBException(e);
2215
                } catch (ParserConfigurationException e) {
2216
                        throw new EJBException(e);
2217
                } catch (TransformerException e) {
2218
                        throw new EJBException(e);
2219
                } catch (IOException e) {
2220
                        throw new EJBException(e);
2221
                } catch (NamingException e) {
2222
                        throw new EJBException(e);
2223
                } catch (JMSException e) {
2224
                        throw new EJBException(e);
2225
                }
2226
                finally {
2227
                        try {
2228
                                if (sender != null)
2229
                                        sender.close();
2230
                                if (session != null)
2231
                                        session.close();
2232
                                if (qConn != null)
2233
                                        qConn.close();
2234
                        }
2235
                        catch (JMSException e) {
2236
                                logger.warn(e);
2237
                        }
2238
                }
2239
        }
2240

    
2241
        /**
2242
         * Sends a optimize message to the solr server
2243
         *
2244
         * @param httpClient
2245
         * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive
2246
         *                                         calls to stop the recursion
2247
         * @throws UnsupportedEncodingException
2248
         * @throws IOException
2249
         * @throws HttpException
2250
         */
2251
        private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException {
2252
                PostMethod method = null;
2253
                try {
2254
                        logger.debug("Optimize retry: " + retryCount);
2255
                        method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2256
                        method.setRequestEntity(new StringRequestEntity("<optimize/>", "text/xml", "iso8859-1"));
2257
                        int statusCode = httpClient.executeMethod(method);
2258
                        logger.debug("HTTP status: " + statusCode);
2259
                        String response = method.getResponseBodyAsString();
2260
                        logger.debug(response);
2261
                        if (statusCode != 200 && retryCount < 2) {
2262
                                try {
2263
                                        Thread.sleep(10000); //Give Solr a little time to be available
2264
                                } catch (InterruptedException e) {
2265
                                }
2266
                                sendOptimize(httpClient, retryCount + 1);
2267
                        }
2268
                }
2269
                finally {
2270
                        if (method != null)
2271
                                method.releaseConnection();
2272
                }
2273
        }
2274

    
2275
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2276
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2277
                        InsufficientPermissionsException, QuotaExceededException {
2278
                // Validate.
2279
                if (userId == null)
2280
                        throw new ObjectNotFoundException("No user specified");
2281
                if (folderId == null)
2282
                        throw new ObjectNotFoundException("No folder specified");
2283
                String contentType = mimeType;
2284
                if (StringUtils.isEmpty(mimeType))
2285
                        contentType = DEFAULT_MIME_TYPE;
2286
                if (StringUtils.isEmpty(name))
2287
                        throw new ObjectNotFoundException("No file name specified");
2288
                if (dao.existsFolderOrFile(folderId, name))
2289
                        throw new DuplicateNameException("A folder or file with the name '" + name +
2290
                                                "' already exists at this level");
2291

    
2292
                // Do the actual work.
2293
                Folder parent = null;
2294
                try {
2295
                        parent = dao.getEntityById(Folder.class, folderId);
2296
                } catch (final ObjectNotFoundException onfe) {
2297
                        // Supply a more accurate problem description.
2298
                        throw new ObjectNotFoundException("Parent folder not found");
2299
                }
2300
                final User owner = dao.getEntityById(User.class, userId);
2301
                if (!parent.hasWritePermission(owner))
2302
                        throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2303
                final FileHeader file = new FileHeader();
2304
                file.setName(name);
2305
                parent.addFile(file);
2306
                // set file owner to folder owner
2307
                file.setOwner(parent.getOwner());
2308

    
2309
                final Date now = new Date();
2310
                final AuditInfo auditInfo = new AuditInfo();
2311
                auditInfo.setCreatedBy(owner);
2312
                auditInfo.setCreationDate(now);
2313
                auditInfo.setModifiedBy(owner);
2314
                auditInfo.setModificationDate(now);
2315
                file.setAuditInfo(auditInfo);
2316
                // TODO set the proper versioning flag on creation
2317
                file.setVersioned(false);
2318

    
2319
                for (final Permission p : parent.getPermissions()) {
2320
                        final Permission permission = new Permission();
2321
                        permission.setGroup(p.getGroup());
2322
                        permission.setUser(p.getUser());
2323
                        permission.setRead(p.getRead());
2324
                        permission.setWrite(p.getWrite());
2325
                        permission.setModifyACL(p.getModifyACL());
2326
                        file.addPermission(permission);
2327
                }
2328

    
2329
                // Create the file body.
2330
                try {
2331
                        createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2332
                } catch (FileNotFoundException e) {
2333
                        throw new GSSIOException(e);
2334
                }
2335
                touchParentFolders(parent, owner, new Date());
2336
                dao.flush();
2337
                indexFile(file.getId(), false);
2338

    
2339
                return file.getDTO();
2340
        }
2341

    
2342
        /* (non-Javadoc)
2343
         * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFileContents(java.lang.Long, java.lang.Long, java.lang.String, java.io.InputStream)
2344
         */
2345
        public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2346
                if (userId == null)
2347
                        throw new ObjectNotFoundException("No user specified");
2348
                if (fileId == null)
2349
                        throw new ObjectNotFoundException("No file specified");
2350
                String contentType = mimeType;
2351

    
2352
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2353

    
2354
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2355
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2356
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2357
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2358
                        contentType = identifyMimeType(file.getName());
2359

    
2360
                final User owner = dao.getEntityById(User.class, userId);
2361
                if (!file.hasWritePermission(owner))
2362
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2363
                final Date now = new Date();
2364
                final AuditInfo auditInfo = new AuditInfo();
2365
                auditInfo.setCreatedBy(owner);
2366
                auditInfo.setCreationDate(now);
2367
                auditInfo.setModifiedBy(owner);
2368
                auditInfo.setModificationDate(now);
2369
                try {
2370
                        createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2371
                } catch (FileNotFoundException e) {
2372
                        throw new GSSIOException(e);
2373
                }
2374
                Folder parent = file.getFolder();
2375
                touchParentFolders(parent, owner, new Date());
2376

    
2377
                indexFile(fileId, false);
2378
                return file.getDTO();
2379
        }
2380

    
2381
        /**
2382
         * Helper method for identifying mime type by examining the filename extension
2383
         *
2384
         * @param filename
2385
         * @return the mime type
2386
         */
2387
        private String identifyMimeType(String filename) {
2388
                if (filename.indexOf('.') != -1) {
2389
                        String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2390
                        if (".doc".equals(extension))
2391
                                return "application/msword";
2392
                        else if (".xls".equals(extension))
2393
                                return "application/vnd.ms-excel";
2394
                        else if (".ppt".equals(extension))
2395
                                return "application/vnd.ms-powerpoint";
2396
                        else if (".pdf".equals(extension))
2397
                                return "application/pdf";
2398
                        else if (".gif".equals(extension))
2399
                                return "image/gif";
2400
                        else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2401
                                return "image/jpeg";
2402
                        else if (".tiff".equals(extension) || ".tif".equals(extension))
2403
                                return "image/tiff";
2404
                        else if (".png".equals(extension))
2405
                                return "image/png";
2406
                        else if (".bmp".equals(extension))
2407
                                return "image/bmp";
2408
                }
2409
                // when all else fails assign the default mime type
2410
                return DEFAULT_MIME_TYPE;
2411
        }
2412

    
2413
        /**
2414
         * Helper method to create a new file body and attach it as the current body
2415
         * of the provided file header.
2416
         *
2417
         * @param name the original file name
2418
         * @param mimeType the content type
2419
         * @param fileSize the uploaded file size
2420
         * @param filePath the uploaded file full path
2421
         * @param header the file header that will be associated with the new body
2422
         * @param auditInfo the audit info
2423
         * @param owner the owner of the file
2424
         * @throws FileNotFoundException
2425
         * @throws QuotaExceededException
2426
         */
2427
        private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2428
                                FileHeader header, AuditInfo auditInfo)
2429
                        throws FileNotFoundException, QuotaExceededException {
2430

    
2431
                long currentTotalSize = 0;
2432
                if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2433
                        currentTotalSize = header.getTotalSize();
2434
                Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2435
                if(quotaLeft < fileSize-currentTotalSize) {
2436
                        // quota exceeded -> delete the file
2437
                        deleteActualFile(filePath);
2438
                        throw new QuotaExceededException("Not enough free space available");
2439
                }
2440

    
2441
                FileBody body = new FileBody();
2442

    
2443
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2444
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2445
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2446
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2447
                        body.setMimeType(identifyMimeType(name));
2448
                else
2449
                        body.setMimeType(mimeType);
2450
                body.setAuditInfo(auditInfo);
2451
                body.setFileSize(fileSize);
2452
                body.setOriginalFilename(name);
2453
                body.setStoredFilePath(filePath);
2454
                //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2455
                if(!header.isVersioned() && header.getCurrentBody() != null){
2456
                        header.setCurrentBody(null);
2457
                        if (header.getBodies() != null) {
2458
                                Iterator<FileBody> it = header.getBodies().iterator();
2459
                                while(it.hasNext()){
2460
                                        FileBody bo = it.next();
2461
                                        deleteActualFile(bo.getStoredFilePath());
2462
                                        it.remove();
2463
                                        dao.delete(bo);
2464
                                }
2465
                        }
2466
                }
2467

    
2468
                dao.flush();
2469
                header.addBody(body);
2470
                header.setAuditInfo(auditInfo);
2471

    
2472
                dao.create(body);
2473
        }
2474

    
2475

    
2476
        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2477
        public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2478
                if (userId == null)
2479
                        throw new ObjectNotFoundException("No user specified");
2480
                User owner = dao.getEntityById(User.class, userId);
2481
                if(owner == null)
2482
                        throw new ObjectNotFoundException("No user specified");
2483
                long start = 0, end = 0;
2484
                if (logger.isDebugEnabled())
2485
                        start = System.currentTimeMillis();
2486
                File result = new File(generateRepositoryFilePath());
2487
                try {
2488
                        final FileOutputStream output = new FileOutputStream(result);
2489
                        final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2490
                        int n = 0;
2491

    
2492
                        while (-1 != (n = stream.read(buffer)))
2493
                                output.write(buffer, 0, n);
2494
                        output.close();
2495
                        stream.close();
2496
                } catch (IOException e) {
2497
                        if (!result.delete())
2498
                                logger.warn("Could not delete " + result.getPath());
2499
                        throw e;
2500
                }
2501
                if (logger.isDebugEnabled()) {
2502
                        end = System.currentTimeMillis();
2503
                        logger.debug("Time to upload: " + (end - start) + " (msec)");
2504
                }
2505
                return result;
2506
        }
2507

    
2508

    
2509
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2510

    
2511
                if (userId == null)
2512
                        throw new ObjectNotFoundException("No user specified");
2513
                User user = dao.getEntityById(User.class, userId);
2514
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2515
                if(status == null){
2516
                        status = new FileUploadStatus();
2517
                        status.setOwner(user);
2518
                        status.setFilename(filename);
2519
                        status.setBytesUploaded(bytesTransfered);
2520
                        status.setFileSize(fileSize);
2521
                        dao.create(status);
2522
                }
2523
                else{
2524
                        status.setBytesUploaded(bytesTransfered);
2525
                        status.setFileSize(fileSize);
2526
                        dao.update(status);
2527
                }
2528

    
2529
        }
2530

    
2531
        public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2532
                if (userId == null)
2533
                        throw new ObjectNotFoundException("No user specified");
2534
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2535
                if(status != null)
2536
                        dao.delete(status);
2537
        }
2538

    
2539
        @Override
2540
        public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2541
                return dao.getFileUploadStatus(userId, fileName);
2542
        }
2543

    
2544
        @Override
2545
        public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2546
                if (userId == null)
2547
                        throw new ObjectNotFoundException("No user specified");
2548
                if (folderId == null)
2549
                        throw new ObjectNotFoundException("No folder specified");
2550
                final User user = dao.getEntityById(User.class, userId);
2551
                final Folder folder = dao.getEntityById(Folder.class, folderId);
2552
                // Check permissions
2553
                if (!folder.hasReadPermission(user))
2554
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2555
                List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2556
                if (folder.hasReadPermission(user))
2557
                        for (Folder f : folder.getSubfolders())
2558
                                if (f.hasReadPermission(user) && !f.isDeleted())
2559
                                        subfolders.add(f.getDTO());
2560
                FolderDTO result = folder.getDTO();
2561
                result.setSubfolders(subfolders);
2562
                return folder.getDTO();
2563
        }
2564

    
2565
        @Override
2566
        public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2567
                if (userId == null)
2568
                        throw new ObjectNotFoundException("No user specified");
2569
                if (folderId == null)
2570
                        throw new ObjectNotFoundException("No folder specified");
2571
                User user = dao.getEntityById(User.class, callingUserId);
2572
                Folder folder = dao.getEntityById(Folder.class, folderId);
2573
                // Check permissions
2574
                if (!folder.hasReadPermission(user))
2575
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2576

    
2577
                FolderDTO result = folder.getDTO();
2578
                result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2579
                return result;
2580
        }
2581

    
2582
        @Override
2583
        public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2584
                        throws ObjectNotFoundException, InsufficientPermissionsException {
2585
                if (userId == null)
2586
                        throw new ObjectNotFoundException("No user specified");
2587
                if (fileId == null)
2588
                        throw new ObjectNotFoundException("No file specified");
2589
                if (version < 1)
2590
                        throw new ObjectNotFoundException("No valid version specified");
2591
                User user = dao.getEntityById(User.class, userId);
2592
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2593
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2594
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2595
                FileBody body = dao.getFileVersion(fileId, version);
2596
                return body.getDTO();
2597
        }
2598

    
2599
        @Override
2600
        public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2601
                if (userId == null)
2602
                        throw new ObjectNotFoundException("No user specified");
2603
                User user = dao.getEntityById(User.class, userId);
2604
                user.setAcceptedPolicy(isAccepted);
2605
                return user;
2606
        }
2607

    
2608
        @Override
2609
        public void updateAccounting(User user, Date date, long bandwidthDiff) {
2610
                dao.updateAccounting(user, date, bandwidthDiff);
2611
        }
2612

    
2613
        @Override
2614
        public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2615
                if (userId == null)
2616
                        throw new ObjectNotFoundException("No user specified");
2617
                if (folderId == null)
2618
                        throw new ObjectNotFoundException("No folder specified");
2619
                User user = dao.getEntityById(User.class, userId);
2620
                Folder folder = dao.getEntityById(Folder.class, folderId);
2621
                // Check permissions
2622
                if (!folder.hasReadPermission(user))
2623
                        return false;
2624
                return true;
2625
        }
2626

    
2627
        @Override
2628
        public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2629
                if (userId == null)
2630
                        throw new ObjectNotFoundException("No user specified");
2631
                User user = dao.getEntityById(User.class, userId);
2632
                user.generateWebDAVPassword();
2633
                return user.getWebDAVPassword();
2634
        }
2635

    
2636
        @Override
2637
        public Invitation findInvite(String code) {
2638
                if (code == null)
2639
                        return null;
2640
                return dao.findInvite(code);
2641
        }
2642

    
2643
        @Override
2644
        public void createLdapUser(String username, String firstname, String lastname, String email, String password) {
2645
                LDAPConnection lc = new LDAPConnection();
2646
        LDAPAttributeSet attributeSet = new LDAPAttributeSet();
2647
        attributeSet.add(new LDAPAttribute("objectClass",
2648
                        getConfiguration().getString("objectClass")));
2649
        attributeSet.add(new LDAPAttribute("uid", username));
2650
        attributeSet.add(new LDAPAttribute("cn", new String[]{firstname + " " + lastname}));
2651
        attributeSet.add(new LDAPAttribute("sn", lastname));
2652
        attributeSet.add(new LDAPAttribute("givenName", firstname));
2653
        attributeSet.add(new LDAPAttribute("mail", email));
2654
        attributeSet.add(new LDAPAttribute("userPassword", password));
2655
        String dn = "uid=" + username + "," + getConfiguration().getString("baseDn");
2656
        LDAPEntry newEntry = new LDAPEntry(dn, attributeSet);
2657
        try {
2658
                lc.connect(getConfiguration().getString("ldapHost"), LDAPConnection.DEFAULT_PORT);
2659
                lc.bind(LDAPConnection.LDAP_V3, getConfiguration().getString("bindDn"),
2660
                                getConfiguration().getString("bindPassword").getBytes("UTF8"));
2661
                lc.add(newEntry);
2662
                logger.info("Successfully added LDAP account: " + dn);
2663
                lc.disconnect();
2664
        } catch(LDAPException e) {
2665
                throw new RuntimeException(e);
2666
        } catch(UnsupportedEncodingException e) {
2667
                throw new RuntimeException(e);
2668
        }
2669

    
2670
        }
2671

    
2672
}