Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (96.1 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.Nonce;
35
import gr.ebs.gss.server.domain.Permission;
36
import gr.ebs.gss.server.domain.User;
37
import gr.ebs.gss.server.domain.dto.FileBodyDTO;
38
import gr.ebs.gss.server.domain.dto.FileHeaderDTO;
39
import gr.ebs.gss.server.domain.dto.FolderDTO;
40
import gr.ebs.gss.server.domain.dto.GroupDTO;
41
import gr.ebs.gss.server.domain.dto.PermissionDTO;
42
import gr.ebs.gss.server.domain.dto.StatsDTO;
43
import gr.ebs.gss.server.domain.dto.UserDTO;
44

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

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

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

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

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

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

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

    
136

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

    
142
        private void touchParentFolders(Folder folder, User modifiedBy, Date modificationDate) {
143
                Folder f = folder;
144
                while (f!=null) {
145
                        AuditInfo ai = f.getAuditInfo();
146
                        ai.setModifiedBy(modifiedBy);
147
                        ai.setModificationDate(modificationDate);
148
                        f.setAuditInfo(ai);
149
                        f = f.getParent();
150
                }
151
        }
152

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

    
161
        /*
162
         * (non-Javadoc)
163
         *
164
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolder(java.lang.Long)
165
         */
166
        public FolderDTO getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
167
                if (userId == null)
168
                        throw new ObjectNotFoundException("No user specified");
169
                if (folderId == null)
170
                        throw new ObjectNotFoundException("No folder specified");
171
                final User user = dao.getEntityById(User.class, userId);
172
                final Folder folder = dao.getEntityById(Folder.class, folderId);
173
                // Check permissions
174
                if (!folder.hasReadPermission(user))
175
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
176
                return folder.getDTO();
177
        }
178

    
179
        /* (non-Javadoc)
180
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUser(java.lang.Long)
181
         */
182
        public User getUser(Long userId) throws ObjectNotFoundException {
183
                if (userId == null)
184
                        throw new ObjectNotFoundException("No user specified");
185
                return dao.getEntityById(User.class, userId);
186
        }
187

    
188
        /* (non-Javadoc)
189
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserDTO(java.lang.Long)
190
         */
191
        public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
192
                return getUser(userId).getDTO();
193
        }
194

    
195
        /*
196
         * (non-Javadoc)
197
         *
198
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroup(java.lang.Long)
199
         */
200
        public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
201
                if (groupId == null)
202
                        throw new ObjectNotFoundException("No group specified");
203
                final Group group = dao.getEntityById(Group.class, groupId);
204
                return group.getDTO();
205
        }
206

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

    
221
        /*
222
         * (non-Javadoc)
223
         *
224
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroups(java.lang.Long)
225
         */
226
        public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
227
                if (userId == null)
228
                        throw new ObjectNotFoundException("No user specified");
229
                final List<Group> groups = dao.getGroups(userId);
230
                final List<GroupDTO> result = new ArrayList<GroupDTO>();
231
                for (final Group g : groups)
232
                        result.add(g.getDTO());
233
                return result;
234
        }
235

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

    
256
        /*
257
         * (non-Javadoc)
258
         *
259
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsers(java.lang.Long,
260
         *      java.lang.Long)
261
         */
262
        public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
263
                // Validate.
264
                if (userId == null)
265
                        throw new ObjectNotFoundException("No user specified");
266
                if (groupId == null)
267
                        throw new ObjectNotFoundException("No group specified");
268

    
269
                // Do the actual work.
270
                final List<User> users = dao.getUsers(groupId);
271
                final List<UserDTO> result = new ArrayList<UserDTO>();
272
                for (final User u : users)
273
                        result.add(u.getDTO());
274
                return result;
275
        }
276

    
277
        @Override
278
        public FolderDTO createFolder(Long userId, Long parentId, String name)
279
                        throws DuplicateNameException, ObjectNotFoundException, InsufficientPermissionsException {
280
                // Validate.
281
                if (userId == null)
282
                        throw new ObjectNotFoundException("No user specified");
283
                if (StringUtils.isEmpty(name))
284
                        throw new ObjectNotFoundException("New folder name is empty");
285
                if (parentId == null)
286
                        throw new ObjectNotFoundException("No parent specified");
287
                if (dao.existsFolderOrFile(parentId, name))
288
                        throw new DuplicateNameException("A folder or file with the name '" +
289
                                                name + "' already exists at this level");
290

    
291
                User creator = dao.getEntityById(User.class, userId);
292

    
293
                Folder parent = null;
294
                try {
295
                        parent = dao.getEntityById(Folder.class, parentId);
296
                } catch (ObjectNotFoundException onfe) {
297
                        // Supply a more accurate problem description.
298
                        throw new ObjectNotFoundException("Parent folder not found");
299
                }
300
                if (!parent.hasWritePermission(creator))
301
                        throw new InsufficientPermissionsException("You don't have the permissions" +
302
                                        " to write to this folder");
303

    
304
                // Do the actual work.
305
                return createFolder(name, parent, creator);
306
        }
307

    
308
        /**
309
         * Create a new folder with the provided name, parent and owner.
310
         *
311
         * @param name
312
         * @param parent
313
         * @param creator
314
         * @return the new folder
315
         */
316
        private FolderDTO createFolder(String name, Folder parent, User creator) {
317
                Folder folder = new Folder();
318
                folder.setName(name);
319
                if (parent != null) {
320
                        parent.addSubfolder(folder);
321
                        folder.setOwner(parent.getOwner());
322
                } else
323
                        folder.setOwner(creator);
324

    
325
                Date now = new Date();
326
                AuditInfo auditInfo = new AuditInfo();
327
                auditInfo.setCreatedBy(creator);
328
                auditInfo.setCreationDate(now);
329
                auditInfo.setModifiedBy(creator);
330
                auditInfo.setModificationDate(now);
331
                folder.setAuditInfo(auditInfo);
332
                touchParentFolders(folder, auditInfo.getModifiedBy(), auditInfo.getModificationDate());
333

    
334
                if (parent != null)
335
                        for (Permission p : parent.getPermissions()) {
336
                                Permission permission = new Permission();
337
                                permission.setGroup(p.getGroup());
338
                                permission.setUser(p.getUser());
339
                                permission.setRead(p.getRead());
340
                                permission.setWrite(p.getWrite());
341
                                permission.setModifyACL(p.getModifyACL());
342
                                folder.addPermission(permission);
343
                        }
344
                else {
345
                        Permission permission = new Permission();
346
                        permission.setUser(creator);
347
                        permission.setRead(true);
348
                        permission.setWrite(true);
349
                        permission.setModifyACL(true);
350
                        folder.addPermission(permission);
351
                }
352
                dao.create(folder);
353
                return folder.getDTO();
354
        }
355

    
356
        /*
357
         * Deletes the given folder and all its subfolders and files
358
         * Only the permissions for top folder are checked
359
         *
360
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFolder(java.lang.Long,
361
         *      java.lang.Long)
362
         */
363
        public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
364
                // Validate.
365
                if (userId == null)
366
                        throw new ObjectNotFoundException("No user specified");
367
                if (folderId == null)
368
                        throw new ObjectNotFoundException("No folder specified");
369

    
370
                // Do the actual work.
371
                final Folder folder = dao.getEntityById(Folder.class, folderId);
372
                final Folder parent = folder.getParent();
373
                if (parent == null)
374
                        throw new ObjectNotFoundException("Deleting the root folder is not allowed");
375
                final User user = dao.getEntityById(User.class, userId);
376
                if (!folder.hasDeletePermission(user)) {
377
                        logger.info("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
378
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete folder " + folder.getName() + "(" + folder.getId() + ")");
379
                }
380
                removeSubfolderFiles(folder);
381
                parent.removeSubfolder(folder);
382
                dao.delete(folder);
383
                touchParentFolders(parent, user, new Date());
384
        }
385

    
386
        /**
387
         * Traverses the folder and deletes all actual files (file system)
388
         * regardless of permissions
389
         *
390
         * @param folder
391
         */
392
        private void removeSubfolderFiles(Folder folder) {
393
                //remove files for all subfolders
394
                for (Folder subfolder:folder.getSubfolders())
395
                        removeSubfolderFiles(subfolder);
396
                //remove this folder's file bodies (actual files)
397
                for (FileHeader file:folder.getFiles()) {
398
                        for (FileBody body:file.getBodies())
399
                                deleteActualFile(body.getStoredFilePath());
400
                        indexFile(file.getId(), true);
401
                }
402
        }
403

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

    
423
        @Override
424
        public FolderDTO modifyFolder(Long userId, Long folderId, String folderName)
425
                        throws InsufficientPermissionsException, ObjectNotFoundException, DuplicateNameException {
426

    
427
                // Validate.
428
                if (userId == null)
429
                        throw new ObjectNotFoundException("No user specified");
430
                if (folderId == null)
431
                        throw new ObjectNotFoundException("No folder specified");
432
                if (StringUtils.isEmpty(folderName))
433
                        throw new ObjectNotFoundException("New folder name is empty");
434

    
435
                Folder folder = dao.getEntityById(Folder.class, folderId);
436
                User user = dao.getEntityById(User.class, userId);
437
                if (!folder.hasWritePermission(user))
438
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
439

    
440
                Folder parent = folder.getParent();
441
                if (parent != null)
442
                        if (!folder.getName().equals(folderName) && dao.existsFolderOrFile(parent.getId(), folderName))
443
                                throw new DuplicateNameException("A folder or file with the name '" + folderName + "' already exists at this level");
444

    
445
                // Do the actual modification.
446
                folder.setName(folderName);
447
                dao.update(folder);
448
                touchParentFolders(folder, user, new Date());
449
                return folder.getDTO();
450
        }
451

    
452
        /*
453
         * (non-Javadoc)
454
         *
455
         * @see gr.ebs.gss.server.ejb.ExternalAPI#createGroup(java.lang.Long,
456
         *      java.lang.String)
457
         */
458
        public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
459
                // Validate.
460
                if (userId == null)
461
                        throw new ObjectNotFoundException("No user specified");
462
                if (StringUtils.isEmpty(name))
463
                        throw new ObjectNotFoundException("New group name is empty");
464
                if (name.indexOf('/')>=0)
465
                        throw new IllegalArgumentException("Character '/' is not allowed in group name");
466
                if (dao.existsGroup(userId, name))
467
                        throw new DuplicateNameException("A group with the name '" + name + "' already exists");
468

    
469
                // TODO: Check permissions
470

    
471
                final User owner = dao.getEntityById(User.class, userId);
472

    
473
                // Do the actual work.
474
                owner.createGroup(name);
475
        }
476

    
477
        /*
478
         * (non-Javadoc)
479
         *
480
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteGroup(java.lang.Long,
481
         *      java.lang.Long)
482
         */
483
        public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
484
                // Validate.
485
                if (userId == null)
486
                        throw new ObjectNotFoundException("No user specified");
487
                if (groupId == null)
488
                        throw new ObjectNotFoundException("No group specified");
489

    
490
                // Do the actual work.
491
                final User owner = dao.getEntityById(User.class, userId);
492
                final Group group = dao.getEntityById(Group.class, groupId);
493
                // Only delete the group if actually owned by the user.
494
                if (group.getOwner().equals(owner)) {
495
                        List<Folder> folders = dao.getFoldersPermittedForGroup(userId, groupId);
496
                        for (Folder f : folders){
497
                                f.getPermissions().removeAll(group.getPermissions());
498
                                for(FileHeader file : f.getFiles())
499
                                        file.getPermissions().removeAll(group.getPermissions());
500
                        }
501
                        List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
502
                        for(FileHeader h : files)
503
                                h.getPermissions().removeAll(group.getPermissions());
504
                        owner.removeSpecifiedGroup(group);
505
                        dao.delete(group);
506
                }
507
                else throw new InsufficientPermissionsException("You are not the owner of this group");
508
        }
509

    
510
        @Override
511
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
512
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
513
                        InsufficientPermissionsException, QuotaExceededException {
514
                File file = null;
515
                try {
516
                        file = uploadFile(stream, userId);
517
                } catch ( IOException ioe) {
518
                        // Supply a more accurate problem description.
519
                        throw new GSSIOException("Problem creating file",ioe);
520
                }
521
                return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
522
        }
523

    
524
        /* (non-Javadoc)
525
         * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
526
         */
527
        public void indexFile(Long fileId, boolean delete) {
528
                Connection qConn = null;
529
                Session session = null;
530
                MessageProducer sender = null;
531
                try {
532
                        Context jndiCtx = new InitialContext();
533
                        ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
534
                        Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
535
                        qConn = factory.createConnection();
536
                        session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
537
                        sender = session.createProducer(queue);
538

    
539
                        MapMessage map = session.createMapMessage();
540
                        map.setObject("id", fileId);
541
                        map.setBoolean("delete", delete);
542
                        sender.send(map);
543
                }
544
                catch (NamingException e) {
545
                        logger.error("Index was not updated: ", e);
546
                }
547
                catch (JMSException e) {
548
                        logger.error("Index was not updated: ", e);
549
                }
550
                finally {
551
                        try {
552
                                if (sender != null)
553
                                        sender.close();
554
                                if (session != null)
555
                                        session.close();
556
                                if (qConn != null)
557
                                        qConn.close();
558
                        }
559
                        catch (JMSException e) {
560
                                logger.warn(e);
561
                        }
562
                }
563
        }
564

    
565

    
566

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

    
592
        /*
593
         * (non-Javadoc)
594
         *
595
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFile(java.lang.Long,
596
         *      java.lang.Long)
597
         */
598
        public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
599
                // Validate.
600
                if (userId == null)
601
                        throw new ObjectNotFoundException("No user specified");
602
                if (fileId == null)
603
                        throw new ObjectNotFoundException("No file specified");
604

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

    
620
        private void deleteActualFile(String filePath) {
621
                if (filePath == null)
622
                        return;
623
                File file = new File(filePath);
624
                if (!file.delete())
625
                        logger.error("Could not delete file " + filePath);
626
        }
627

    
628
        /*
629
         * (non-Javadoc)
630
         *
631
         * @see gr.ebs.gss.server.ejb.ExternalAPI#createTag(java.lang.Long,
632
         *      java.lang.Long, java.lang.String)
633
         */
634
        public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
635
                if (userId == null)
636
                        throw new ObjectNotFoundException("No user specified");
637
                if (fileHeaderId == null)
638
                        throw new ObjectNotFoundException("No file specified");
639
                if (StringUtils.isEmpty(tag))
640
                        throw new ObjectNotFoundException("Tag is empty");
641

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

    
651
        /* (non-Javadoc)
652
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserTags(java.lang.Long)
653
         */
654
        @WebMethod(operationName = "getUserTags")
655
        public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
656
                return dao.getUserTags(userId);
657
        }
658

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

    
671
                User user = dao.getEntityById(User.class, userId);
672
                if (!file.hasWritePermission(user))
673
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
674

    
675
                if (name != null)
676
                        file.setName(name);
677
                if (modificationDate != null) {
678
                        file.getAuditInfo().setModificationDate(modificationDate);
679
                        file.getAuditInfo().setModifiedBy(user);
680
                }
681
                List<FileTag> tags = file.getFileTags();
682

    
683
                if (tagSet != null) {
684
                        Iterator<FileTag> i = tags.iterator();
685
                        while (i.hasNext()) {
686
                                FileTag tag = i.next();
687
                                i.remove();
688
                                tag.setFile(null);
689
                                user.removeTag(tag);
690
                                dao.delete(tag);
691
                        }
692
                        dao.flush();
693
                        StringTokenizer st = new StringTokenizer(tagSet, ",");
694
                        while (st.hasMoreTokens())
695
                                new FileTag(user, file, st.nextToken().trim());
696
                }
697
                touchParentFolders(parent, user, new Date());
698

    
699
                // Re-index the file if it was modified.
700
                if (name != null || tagSet != null)
701
                        indexFile(fileId, false);
702
        }
703

    
704
        @Override
705
        public InputStream getFileContents(Long userId, Long fileId)
706
                        throws ObjectNotFoundException, InsufficientPermissionsException {
707
                if (userId == null)
708
                        throw new ObjectNotFoundException("No user specified");
709
                if (fileId == null)
710
                        throw new ObjectNotFoundException("No file specified");
711

    
712
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
713
                User user = dao.getEntityById(User.class, userId);
714
                if (!header.hasReadPermission(user)) {
715
                        logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
716
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
717
                }
718

    
719
                File f = new File(header.getCurrentBody().getStoredFilePath());
720
                try {
721
                        return new FileInputStream(f);
722
                } catch (FileNotFoundException e) {
723
                        logger.error("Could not locate the contents of file " + f.getAbsolutePath());
724
                        throw new ObjectNotFoundException("The file contents could not be located");
725
                }
726
        }
727

    
728
        /* (non-Javadoc)
729
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
730
         */
731
        public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
732
                if (userId == null)
733
                        throw new ObjectNotFoundException("No user specified");
734
                if (fileId == null)
735
                        throw new ObjectNotFoundException("No file specified");
736
                if (bodyId == null)
737
                        throw new ObjectNotFoundException("No file specified");
738

    
739
                final FileHeader header = dao.getEntityById(FileHeader.class, fileId);
740
                final FileBody body = dao.getEntityById(FileBody.class, bodyId);
741
                final User user = dao.getEntityById(User.class, userId);
742
                if (!header.hasReadPermission(user)) {
743
                        logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
744
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
745
                }
746

    
747
                File f = new File(body.getStoredFilePath());
748
                try {
749
                        return new FileInputStream(f);
750
                } catch (FileNotFoundException e) {
751
                        logger.error("Could not locate the contents of file " + f.getAbsolutePath());
752
                        throw new ObjectNotFoundException("The file contents could not be located");
753
                }
754
        }
755

    
756
        /* (non-Javadoc)
757
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFile(java.lang.Long, java.lang.Long)
758
         */
759
        public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
760
                if (userId == null)
761
                        throw new ObjectNotFoundException("No user specified");
762
                if (fileId == null)
763
                        throw new ObjectNotFoundException("No file specified");
764
                final User user = dao.getEntityById(User.class, userId);
765
                final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
766
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
767
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
768
                return file.getDTO();
769
        }
770

    
771
        @Override
772
        public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
773
                if (userId == null)
774
                        throw new ObjectNotFoundException("No user specified");
775
                if (fileId == null)
776
                        throw new ObjectNotFoundException("No file specified");
777
                User user = dao.getEntityById(User.class, userId);
778
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
779
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
780
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
781
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
782
                return body.getDTO();
783
        }
784

    
785
        @Override
786
        public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
787
                        throws ObjectNotFoundException {
788
                if (ownerId == null)
789
                        throw new ObjectNotFoundException("No user specified");
790
                if (StringUtils.isEmpty(path))
791
                        throw new ObjectNotFoundException("No path specified");
792

    
793
                User owner = dao.getEntityById(User.class, ownerId);
794
                List<String> pathElements = new ArrayList<String>();
795
                StringTokenizer st = new StringTokenizer(path, "/");
796
                while (st.hasMoreTokens())
797
                        pathElements.add(st.nextToken());
798
                if (pathElements.size() < 1)
799
                        return getRootFolder(owner.getId());
800
                // Store the last element, since it requires special handling.
801
                String lastElement = pathElements.remove(pathElements.size() - 1);
802
                FolderDTO cursor = getRootFolder(owner.getId());
803
                // Traverse and verify the specified folder path.
804
                for (String pathElement : pathElements) {
805
                        cursor = getFolder(cursor.getId(), pathElement);
806
                        if (cursor.isDeleted())
807
                                throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
808
                }
809

    
810
                // Use the lastElement to retrieve the actual resource.
811
                Object resource = null;
812
                try {
813
                        FileHeaderDTO file = getFile(cursor.getId(), lastElement);
814
                        if (ignoreDeleted && file.isDeleted())
815
                                throw new ObjectNotFoundException("Resource not found");
816
                        resource = file;
817
                } catch (ObjectNotFoundException e) {
818
                        // Perhaps the requested resource is not a file, so
819
                        // check for folders as well.
820
                        FolderDTO folder = getFolder(cursor.getId(), lastElement);
821
                        if (ignoreDeleted && folder.isDeleted())
822
                                throw new ObjectNotFoundException("Resource not found");
823
                        resource = folder;
824
                }
825
                return resource;
826
        }
827

    
828
        /**
829
         * Retrieve a file for the specified user that has the specified name and
830
         * its parent folder has id equal to folderId.
831
         *
832
         * @param userId the ID of the current user
833
         * @param folderId the ID of the parent folder
834
         * @param name the name of the requested file
835
         * @return the file found
836
         * @throws ObjectNotFoundException if the specified folder or file was not
837
         *             found, with the exception message mentioning the precise
838
         *             problem
839
         */
840
        private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
841
                if (folderId == null)
842
                        throw new ObjectNotFoundException("No parent folder specified");
843
                if (StringUtils.isEmpty(name))
844
                        throw new ObjectNotFoundException("No file specified");
845

    
846
                FileHeader file = dao.getFile(folderId, name);
847
                return file.getDTO();
848
        }
849

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

    
867
                Folder folder = dao.getFolder(parentId, name);
868
                return folder.getDTO();
869
        }
870

    
871
        private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
872
                File file = null;
873
                try {
874
                        file = uploadFile(resourceInputStream, userId);
875
                } catch ( IOException ioe) {
876
                        // Supply a more accurate problem description.
877
                        throw new GSSIOException("Problem creating file",ioe);
878
                }
879
                return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
880
        }
881

    
882
        @Override
883
        public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
884
                if (userId == null)
885
                        throw new ObjectNotFoundException("No user specified");
886
                if (fileId == null)
887
                        throw new ObjectNotFoundException("No file specified");
888
                if (StringUtils.isEmpty(dest))
889
                        throw new ObjectNotFoundException("No destination specified");
890

    
891
                Object destination = getResourceAtPath(userId, getParentPath(dest), true);
892
                if (!(destination instanceof FolderDTO))
893
                        throw new ObjectNotFoundException("Destination parent folder not found");
894
                FolderDTO parent = (FolderDTO) destination;
895
                copyFile(userId, fileId, parent.getId(), getLastElement(dest));
896
        }
897

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

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

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

    
927
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
928
                Folder destination = dao.getEntityById(Folder.class, destId);
929
                User user = dao.getEntityById(User.class, userId);
930
                if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
931
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
932
                boolean versioned = file.isVersioned();
933
                int versionsNumber = file.getBodies().size();
934
                FileBody oldestBody = file.getBodies().get(0);
935
                assert oldestBody != null;
936
                File contents = new File(oldestBody.getStoredFilePath());
937
                try {
938
                        createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
939
                        FileHeader copiedFile = dao.getFile(destination.getId(), destName);
940
                        copiedFile.setVersioned(versioned);
941
                        dao.flush();
942
                        if (versionsNumber > 1)
943
                                for (int i = 1; i < versionsNumber; i++) {
944
                                        FileBody body = file.getBodies().get(i);
945
                                        assert body != null;
946
                                        contents = new File(body.getStoredFilePath());
947
                                        updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
948
                                }
949
                        List<FileTag> tags = file.getFileTags();
950
                        for (FileTag tag : tags)
951
                                createTag(userId, copiedFile.getId(), tag.getTag());
952

    
953
                } catch (FileNotFoundException e) {
954
                        throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
955
                }
956

    
957
        }
958

    
959
        @Override
960
        public void copyFolder(Long userId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
961
                if (userId == null)
962
                        throw new ObjectNotFoundException("No user specified");
963
                if (folderId == null)
964
                        throw new ObjectNotFoundException("No folder specified");
965
                if (StringUtils.isEmpty(dest))
966
                        throw new ObjectNotFoundException("No destination specified");
967

    
968
                Object destination = getResourceAtPath(userId, getParentPath(dest), true);
969
                if (!(destination instanceof FolderDTO))
970
                        throw new ObjectNotFoundException("Destination folder not found");
971
                FolderDTO parent = (FolderDTO) destination;
972
                copyFolder(userId, folderId, parent.getId(), getLastElement(dest));
973
        }
974

    
975
        @Override
976
        public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
977
                if (userId == null)
978
                        throw new ObjectNotFoundException("No user specified");
979
                if (folderId == null)
980
                        throw new ObjectNotFoundException("No folder specified");
981
                if (destId == null)
982
                        throw new ObjectNotFoundException("No destination specified");
983
                if (StringUtils.isEmpty(destName))
984
                        throw new ObjectNotFoundException("No destination folder name specified");
985
                Folder folder = dao.getEntityById(Folder.class, folderId);
986
                Folder destination = dao.getEntityById(Folder.class, destId);
987
                User user = dao.getEntityById(User.class, userId);
988
                if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
989
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
990
                createFolder(user.getId(), destination.getId(), destName);
991
        }
992

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

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

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

    
1022
                Folder folder = dao.getEntityById(Folder.class, folderId);
1023
                Folder destination = dao.getEntityById(Folder.class, destId);
1024
                final User user = dao.getEntityById(User.class, userId);
1025
                // XXX: quick fix need to copy only visible items to user (Source
1026
                // for bugs)
1027
                if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
1028
                        return;
1029
                if(folder.isDeleted())//do not copy trashed folder and contents
1030
                        return;
1031
                if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1032
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1033
                createFolder(user.getId(), destination.getId(), destName);
1034
                Folder createdFolder = dao.getFolder(destination.getId(), destName);
1035
                List<FileHeader> files = folder.getFiles();
1036
                if (files != null)
1037
                        for (FileHeader file : files)
1038
                                if(!file.isDeleted())
1039
                                        copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1040
                List<Folder> subFolders = folder.getSubfolders();
1041
                if (subFolders != null)
1042
                        for (Folder sub : subFolders)
1043
                                if(!sub.getId().equals(createdFolder.getId()))
1044
                                        copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1045

    
1046
        }
1047

    
1048
        /**
1049
         * For a provided path, remove the last element and return the rest, that is
1050
         * the path of the parent folder.
1051
         *
1052
         * @param path the specified path
1053
         * @return the path of the parent folder
1054
         * @throws ObjectNotFoundException if the provided string contains no path
1055
         *             delimiters
1056
         */
1057
        private String getParentPath(String path) throws ObjectNotFoundException {
1058
                int lastDelimiter = path.lastIndexOf('/');
1059
                if (lastDelimiter == 0)
1060
                        return "/";
1061
                if (lastDelimiter == -1)
1062
                        // No path found.
1063
                        throw new ObjectNotFoundException("There is no parent in the path: " + path);
1064
                else if (lastDelimiter < path.length() - 1)
1065
                        // Return the part before the delimiter.
1066
                        return path.substring(0, lastDelimiter);
1067
                else {
1068
                        // Remove the trailing delimiter and then recurse.
1069
                        String strippedTrail = path.substring(0, lastDelimiter);
1070
                        return getParentPath(strippedTrail);
1071
                }
1072
        }
1073

    
1074
        /**
1075
         * Get the last element in a path that denotes the file or folder name.
1076
         *
1077
         * @param path the provided path
1078
         * @return the last element in the path
1079
         */
1080
        private String getLastElement(String path) {
1081
                int lastDelimiter = path.lastIndexOf('/');
1082
                if (lastDelimiter == -1)
1083
                        // No path found.
1084
                        return path;
1085
                else if (lastDelimiter < path.length() - 1)
1086
                        // Return the part after the delimiter.
1087
                        return path.substring(lastDelimiter + 1);
1088
                else {
1089
                        // Remove the trailing delimiter and then recurse.
1090
                        String strippedTrail = path.substring(0, lastDelimiter);
1091
                        return getLastElement(strippedTrail);
1092
                }
1093
        }
1094

    
1095
        @Override
1096
        public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1097
                if (userId == null)
1098
                        throw new ObjectNotFoundException("No user specified");
1099
                if (fileId == null)
1100
                        throw new ObjectNotFoundException("No file specified");
1101

    
1102
                // Do the actual work.
1103
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1104
                Folder parent = file.getFolder();
1105
                if (parent == null)
1106
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1107
                User user = dao.getEntityById(User.class, userId);
1108
                if (!file.hasDeletePermission(user))
1109
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1110

    
1111
                file.setDeleted(true);
1112
                dao.update(file);
1113
                touchParentFolders(parent, user, new Date());
1114
        }
1115

    
1116
        @Override
1117
        public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1118
                if (userId == null)
1119
                        throw new ObjectNotFoundException("No user specified");
1120
                if (ownerId == null)
1121
                        throw new ObjectNotFoundException("No owner specified");
1122
                if (fileId == null)
1123
                        throw new ObjectNotFoundException("No file specified");
1124
                if (StringUtils.isEmpty(dest))
1125
                        throw new ObjectNotFoundException("No destination specified");
1126

    
1127
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1128
                if (!(destination instanceof FolderDTO))
1129
                        throw new ObjectNotFoundException("Destination parent folder not found");
1130
                FolderDTO parent = (FolderDTO) destination;
1131
                moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1132
        }
1133

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

    
1145
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1146
                Folder source = file.getFolder();
1147
                Folder destination = dao.getEntityById(Folder.class, destId);
1148

    
1149
                User owner = dao.getEntityById(User.class, userId);
1150
                if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1151
                        throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1152

    
1153
                // if the destination folder belongs to another user:
1154
                if (!file.getOwner().equals(destination.getOwner())) {
1155
                        // (a) check if the destination quota allows the move
1156
                        if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1157
                                throw new QuotaExceededException("Not enough free space available");
1158
                        User newOwner = destination.getOwner();
1159
                        // (b) if quota OK, change the owner of the file
1160
                        file.setOwner(newOwner);
1161
                        // if the file has no permission for the new owner, add it
1162
                        Permission ownerPermission = null;
1163
                        for (final Permission p : file.getPermissions())
1164
                                if (p.getUser() != null)
1165
                                        if (p.getUser().equals(newOwner)) {
1166
                                                ownerPermission = p;
1167
                                                break;
1168
                                        }
1169
                        if (ownerPermission == null) {
1170
                                ownerPermission = new Permission();
1171
                                ownerPermission.setUser(newOwner);
1172
                                file.addPermission(ownerPermission);
1173
                        }
1174
                        ownerPermission.setRead(true);
1175
                        ownerPermission.setWrite(true);
1176
                        ownerPermission.setModifyACL(true);
1177
                }
1178
                // move the file to the destination folder
1179
                file.setFolder(destination);
1180
                touchParentFolders(source, owner, new Date());
1181
                touchParentFolders(destination, owner, new Date());
1182
        }
1183

    
1184
        @Override
1185
        public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1186
                if (userId == null)
1187
                        throw new ObjectNotFoundException("No user specified");
1188
                if (ownerId == null)
1189
                        throw new ObjectNotFoundException("No owner specified");
1190
                if (folderId == null)
1191
                        throw new ObjectNotFoundException("No folder specified");
1192
                if (StringUtils.isEmpty(dest))
1193
                        throw new ObjectNotFoundException("No destination specified");
1194

    
1195
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1196
                if (!(destination instanceof FolderDTO))
1197
                        throw new ObjectNotFoundException("Destination parent folder not found");
1198
                FolderDTO parent = (FolderDTO) destination;
1199
                moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1200
        }
1201

    
1202
        @Override
1203
        public void moveFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1204
                // TODO Simple Move and delete of original folder, in production
1205
                // scenario we must first check individual files and folders permissions
1206
                copyFolderStructure(userId, folderId, destId, destName);
1207
                deleteFolder(userId, folderId);
1208
        }
1209

    
1210
        /* (non-Javadoc)
1211
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getDeletedFiles(java.lang.Long)
1212
         */
1213
        public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1214
                // Validate.
1215
                if (userId == null)
1216
                        throw new ObjectNotFoundException("No user specified");
1217

    
1218
                // Do the actual work.
1219
                final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1220
                final List<FileHeader> files = dao.getDeletedFiles(userId);
1221
                for (final FileHeader f : files)
1222
                        result.add(f.getDTO());
1223
                return result;
1224
        }
1225

    
1226
        @Override
1227
        public void removeFileFromTrash(Long userId, Long fileId)
1228
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1229
                if (userId == null)
1230
                        throw new ObjectNotFoundException("No user specified");
1231
                if (fileId == null)
1232
                        throw new ObjectNotFoundException("No file specified");
1233

    
1234
                // Do the actual work.
1235
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1236
                Folder parent = file.getFolder();
1237
                if (parent == null)
1238
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1239
                User user = dao.getEntityById(User.class, userId);
1240
                if (!file.hasDeletePermission(user))
1241
                        throw new InsufficientPermissionsException("User " + user.getUsername() +
1242
                                                " cannot restore file " + file.getName());
1243

    
1244
                file.setDeleted(false);
1245
                dao.update(file);
1246
                touchParentFolders(parent, user, new Date());
1247
        }
1248

    
1249
        @Override
1250
        public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1251
                if (userId == null)
1252
                        throw new ObjectNotFoundException("No user specified");
1253
                if (folderId == null)
1254
                        throw new ObjectNotFoundException("No folder specified");
1255
                Folder folder = dao.getEntityById(Folder.class, folderId);
1256
                User user = dao.getEntityById(User.class, userId);
1257
                if (!folder.hasDeletePermission(user))
1258
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1259
                folder.setDeleted(true);
1260
                dao.update(folder);
1261
                touchParentFolders(folder, user, new Date());
1262
                for (FileHeader file : folder.getFiles())
1263
                        moveFileToTrash(userId, file.getId());
1264
                for (Folder subFolder : folder.getSubfolders())
1265
                        moveFolderToTrash(userId, subFolder.getId());
1266

    
1267
        }
1268

    
1269
        @Override
1270
        public void removeFolderFromTrash(Long userId, Long folderId)
1271
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1272
                if (userId == null)
1273
                        throw new ObjectNotFoundException("No user specified");
1274
                if (folderId == null)
1275
                        throw new ObjectNotFoundException("No folder specified");
1276
                Folder folder = dao.getEntityById(Folder.class, folderId);
1277
                User user = dao.getEntityById(User.class, userId);
1278
                if (!folder.hasDeletePermission(user))
1279
                        throw new InsufficientPermissionsException("User " + user.getUsername() +
1280
                                                " cannot restore folder " + folder.getName());
1281
                folder.setDeleted(false);
1282
                for (FileHeader file : folder.getFiles())
1283
                        removeFileFromTrash(userId, file.getId());
1284
                for (Folder subFolder : folder.getSubfolders())
1285
                        removeFolderFromTrash(userId, subFolder.getId());
1286
                dao.update(folder);
1287
                touchParentFolders(folder, user, new Date());
1288
        }
1289

    
1290
        @Override
1291
        public List<FolderDTO> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1292
                List<Folder> folders = dao.getDeletedRootFolders(userId);
1293
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1294
                for (Folder folder : folders)
1295
                        result.add(folder.getDTO());
1296
                return result;
1297
        }
1298

    
1299
        @Override
1300
        public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1301
                List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1302
                for (FolderDTO fdto : deletedRootFolders)
1303
                        deleteFolder(userId, fdto.getId());
1304
                List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1305
                for (FileHeaderDTO filedto : deletedFiles)
1306
                        deleteFile(userId, filedto.getId());
1307
        }
1308

    
1309
        @Override
1310
        public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1311
                List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1312
                for (FolderDTO fdto : deletedRootFolders)
1313
                        removeFolderFromTrash(userId, fdto.getId());
1314
                List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1315
                for (FileHeaderDTO filedto : deletedFiles)
1316
                        removeFileFromTrash(userId, filedto.getId());
1317
        }
1318

    
1319
        @Override
1320
        public User createUser(String username, String name, String mail) throws ObjectNotFoundException {
1321
                if (username == null)
1322
                        throw new ObjectNotFoundException("No username specified");
1323
                if (name == null)
1324
                        throw new ObjectNotFoundException("No name specified");
1325

    
1326
                User user = new User();
1327
                user.setUsername(username);
1328
                user.setName(name);
1329
                user.setEmail(mail);
1330
                Date now = new Date();
1331
                AuditInfo auditInfo = new AuditInfo();
1332
                auditInfo.setCreationDate(now);
1333
                auditInfo.setModificationDate(now);
1334
                user.setAuditInfo(auditInfo);
1335
                user.generateAuthToken();
1336
                user.generateWebDAVPassword();
1337
                dao.create(user);
1338
                // Make sure we get an ID in the user object.
1339
                dao.flush();
1340
                // Create the root folder for the user.
1341
                createFolder(user.getName(), null, user);
1342
                return user;
1343
        }
1344

    
1345
        @Override
1346
        public User findUserByEmail(String email) {
1347
                return dao.findUserByEmail(email);
1348
        }
1349

    
1350
        @Override
1351
        public void updateUser(User user) {
1352
                dao.update(user);
1353
        }
1354

    
1355
        @Override
1356
        public User updateUser(String username, String name, String mail) throws ObjectNotFoundException {
1357
                if (username == null)
1358
                        throw new ObjectNotFoundException("No username specified");
1359

    
1360
                User user = dao.getUser(username);
1361
                user.setName(name);
1362
                user.setEmail(mail);
1363
                return user;
1364
        }
1365

    
1366
        @Override
1367
        public User findUser(String username) {
1368
                if (username == null)
1369
                        return null;
1370
                return dao.findUser(username);
1371
        }
1372

    
1373
        @Override
1374
        public User updateUserToken(Long userId) throws ObjectNotFoundException {
1375
                if (userId == null)
1376
                        throw new ObjectNotFoundException("No user specified");
1377
                User user = dao.getEntityById(User.class, userId);
1378
                user.generateAuthToken();
1379
                return user;
1380
        }
1381

    
1382
        /* (non-Javadoc)
1383
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolderPermissions(java.lang.Long, java.lang.Long)
1384
         */
1385
        @Override
1386
        public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1387
                if (userId == null)
1388
                        throw new ObjectNotFoundException("No user specified");
1389
                if (folderId == null)
1390
                        throw new ObjectNotFoundException("No folder specified");
1391
                User user = dao.getEntityById(User.class, userId);
1392
                Folder folder = dao.getEntityById(Folder.class, folderId);
1393
                if(!folder.hasReadPermission(user))
1394
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1395
                Set<Permission> perms = folder.getPermissions();
1396
                Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1397
                for (Permission perm : perms)
1398
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1399
                                result.add(perm.getDTO());
1400
                for (Permission perm : perms)
1401
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1402
                        } else
1403
                                result.add(perm.getDTO());
1404
                return result;
1405

    
1406
        }
1407

    
1408
        /* (non-Javadoc)
1409
         * @see gr.ebs.gss.server.ejb.ExternalAPI#setFolderPermissions(java.lang.Long, java.lang.Long, java.util.Set)
1410
         */
1411
        @Override
1412
        public void setFolderPermissions(Long userId, Long folderId, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1413
                if (userId == null)
1414
                        throw new ObjectNotFoundException("No user specified");
1415
                if (folderId == null)
1416
                        throw new ObjectNotFoundException("No folder specified");
1417
                User user = dao.getEntityById(User.class, userId);
1418
                Folder folder = dao.getEntityById(Folder.class, folderId);
1419
                if(!folder.hasModifyACLPermission(user))
1420
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1421
                // Delete previous entries
1422
                for (Permission perm: folder.getPermissions())
1423
                        dao.delete(perm);
1424
                folder.getPermissions().clear();
1425
                for (PermissionDTO dto : permissions) {
1426
                        if (dto.getUser()!=null && dto.getUser().getId().equals(folder.getOwner().getId()) && (!dto.hasRead() || !dto.hasWrite() || !dto.hasModifyACL()))
1427
                                        throw new InsufficientPermissionsException("Can't remove permissions from owner");
1428
                        // Don't include 'empty' permission
1429
                        if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1430
                        folder.addPermission(getPermission(dto));
1431
                }
1432
                dao.update(folder);
1433
                for (FileHeader fh : folder.getFiles())
1434
                        setFilePermissions(userId, fh.getId(), fh.isReadForAll(), permissions);
1435
                for (Folder sub : folder.getSubfolders())
1436
                        setFolderPermissions(userId, sub.getId(), permissions);
1437
        }
1438

    
1439
        private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1440
                Permission res = new Permission();
1441
                if (dto.getGroup() != null)
1442
                        res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1443
                else if (dto.getUser() != null)
1444
                        if (dto.getUser().getId() == null)
1445
                                res.setUser(dao.getUser(dto.getUser().getUsername()));
1446
                        else
1447
                                res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1448
                res.setRead(dto.hasRead());
1449
                res.setWrite(dto.hasWrite());
1450
                res.setModifyACL(dto.hasModifyACL());
1451
                return res;
1452
        }
1453

    
1454
        /* (non-Javadoc)
1455
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1456
         */
1457
        @Override
1458
        public List<UserDTO> getUsersByUserNameLike(String username) {
1459
                List<User> users = dao.getUsersByUserNameLike(username);
1460
                List<UserDTO> result = new ArrayList<UserDTO>();
1461
                for (User u : users)
1462
                        result.add(u.getDTO());
1463
                return result;
1464

    
1465
        }
1466

    
1467
        /* (non-Javadoc)
1468
         * @see gr.ebs.gss.server.ejb.ExternalAPI#addUserToGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1469
         */
1470
        @Override
1471
        public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1472
                if (userId == null)
1473
                        throw new ObjectNotFoundException("No user specified");
1474
                if (groupId == null)
1475
                        throw new ObjectNotFoundException("No group specified");
1476
                if (userToAddId == null)
1477
                        throw new ObjectNotFoundException("No user to add specified");
1478
                User user = dao.getEntityById(User.class, userId);
1479
                Group group = dao.getEntityById(Group.class, groupId);
1480
                if (!group.getOwner().equals(user))
1481
                        throw new InsufficientPermissionsException();
1482
                User userToAdd = dao.getEntityById(User.class, userToAddId);
1483
                if (group.contains(userToAdd))
1484
                        throw new DuplicateNameException("User already exists in group");
1485
                group.getMembers().add(userToAdd);
1486
                dao.update(group);
1487

    
1488
        }
1489

    
1490
        @Override
1491
        public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1492
                if (userId == null)
1493
                        throw new ObjectNotFoundException("No user specified");
1494
                User user = dao.getEntityById(User.class, userId);
1495
                user.invalidateAuthToken();
1496
                return;
1497
        }
1498

    
1499
        @Override
1500
        public List<FolderDTO> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1501
                if (userId == null)
1502
                        throw new ObjectNotFoundException("No user specified");
1503
                List<Folder> folders = dao.getSharedRootFolders(userId);
1504
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1505
                for (Folder f : folders) {
1506
                        FolderDTO dto = f.getDTO();
1507
                        dto.setSubfolders(getSharedSubfolders(userId, f.getId()));
1508
                        result.add(dto);
1509
                }
1510
                return result;
1511
        }
1512

    
1513
        /* (non-Javadoc)
1514
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeMemberFromGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1515
         */
1516
        @Override
1517
        public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1518
                if (userId == null)
1519
                        throw new ObjectNotFoundException("No user specified");
1520
                if (groupId == null)
1521
                        throw new ObjectNotFoundException("No group specified");
1522
                if (memberId == null)
1523
                        throw new ObjectNotFoundException("No member specified");
1524
                User owner = dao.getEntityById(User.class, userId);
1525
                Group group = dao.getEntityById(Group.class, groupId);
1526
                User member = dao.getEntityById(User.class, memberId);
1527
                if (!group.getOwner().equals(owner))
1528
                        throw new InsufficientPermissionsException("User is not the owner of the group");
1529
                group.removeMemberFromGroup(member);
1530
                dao.update(group);
1531

    
1532
        }
1533

    
1534
        /* (non-Javadoc)
1535
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersSharingFoldersForUser(java.lang.Long)
1536
         */
1537
        @Override
1538
        public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1539
                List<User> users = dao.getUsersSharingFoldersForUser(userId);
1540
                List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1541
                List<UserDTO> res = new ArrayList<UserDTO>();
1542
                for (User u : users)
1543
                        res.add(u.getDTO());
1544
                for(User fu : usersFiles)
1545
                        if(!users.contains(fu))
1546
                                res.add(fu.getDTO());
1547
                return res;
1548
        }
1549

    
1550
        /* (non-Javadoc)
1551
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFilePermissions(java.lang.Long, java.lang.Long)
1552
         */
1553
        @Override
1554
        public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1555
                if (userId == null)
1556
                        throw new ObjectNotFoundException("No user specified");
1557
                if (fileId == null)
1558
                        throw new ObjectNotFoundException("No folder specified");
1559
                User user = dao.getEntityById(User.class, userId);
1560
                FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1561
                if(!folder.hasReadPermission(user))
1562
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1563
                Set<Permission> perms = folder.getPermissions();
1564
                Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1565
                for (Permission perm : perms)
1566
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1567
                                result.add(perm.getDTO());
1568
                for (Permission perm : perms)
1569
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1570
                        } else
1571
                                result.add(perm.getDTO());
1572
                return result;
1573
        }
1574

    
1575
        @Override
1576
        public void setFilePermissions(Long userId, Long fileId, Boolean readForAll, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1577
                if (userId == null)
1578
                        throw new ObjectNotFoundException("No user specified");
1579
                if (fileId == null)
1580
                        throw new ObjectNotFoundException("No folder specified");
1581

    
1582
                User user = dao.getEntityById(User.class, userId);
1583
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1584
                if(!file.hasModifyACLPermission(user))
1585
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1586

    
1587
                if (readForAll != null)
1588
                        if (user.equals(file.getOwner()))
1589
                                file.setReadForAll(readForAll);
1590
                        else
1591
                                throw new InsufficientPermissionsException("Only the owner can change the read-for-all flag");
1592

    
1593
                // Update the file if there was a change.
1594
                if (readForAll != null || permissions != null && !permissions.isEmpty()) {
1595
                        if (permissions != null && !permissions.isEmpty()) {
1596
                                // Delete previous entries
1597
                                for (Permission perm: file.getPermissions())
1598
                                        dao.delete(perm);
1599
                                file.getPermissions().clear();
1600
                                for (PermissionDTO dto : permissions) {
1601
                                        if (dto.getUser()!=null && dto.getUser().getId().equals(file.getOwner().getId()) && (!dto.hasRead() || !dto.hasWrite() || !dto.hasModifyACL()))
1602
                                                throw new InsufficientPermissionsException("Can't remove permissions from owner");
1603
                                        // Don't include 'empty' permission
1604
                                        if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1605
                                        file.addPermission(getPermission(dto));
1606
                                }
1607
                        }
1608

    
1609
                        dao.update(file);
1610
                        Folder parent = file.getFolder();
1611
                        touchParentFolders(parent, user, new Date());
1612
                }
1613
        }
1614

    
1615
        @Override
1616
        public List<FileHeaderDTO> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1617
                if (userId == null)
1618
                        throw new ObjectNotFoundException("No user specified");
1619
                List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1620
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1621
                for (FileHeader f : files)
1622
                        result.add(f.getDTO());
1623
                return result;
1624
        }
1625

    
1626
        @Override
1627
        public List<FileHeaderDTO> getSharedFiles(Long userId) throws ObjectNotFoundException {
1628
                if (userId == null)
1629
                        throw new ObjectNotFoundException("No user specified");
1630
                List<FileHeader> files = dao.getSharedFiles(userId);
1631
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1632
                for (FileHeader f : files)
1633
                        result.add(f.getDTO());
1634
                return result;
1635
        }
1636

    
1637
        @Override
1638
        public List<FolderDTO> getSharedFolders(Long userId) throws ObjectNotFoundException {
1639
                if (userId == null)
1640
                        throw new ObjectNotFoundException("No user specified");
1641
                List<Folder> folders = dao.getSharedFolders(userId);
1642
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1643
                for (Folder f : folders)
1644
                        result.add(f.getDTO());
1645
                return result;
1646
        }
1647

    
1648
        /* (non-Javadoc)
1649
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getSharedFiles(java.lang.Long, java.lang.Long)
1650
         */
1651
        @Override
1652
        public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1653
                if (ownerId == null)
1654
                        throw new ObjectNotFoundException("No owner specified");
1655
                if (callingUserId == null)
1656
                        throw new ObjectNotFoundException("No calling user specified");
1657
                List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1658
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1659
                for (FileHeader f : folders)
1660
                        result.add(f.getDTO());
1661
                return result;
1662
        }
1663

    
1664
        @Override
1665
        public List<FolderDTO> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1666
                if (ownerId == null)
1667
                        throw new ObjectNotFoundException("No owner specified");
1668
                if (callingUserId == null)
1669
                        throw new ObjectNotFoundException("No calling user specified");
1670
                List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1671
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1672
                for (Folder f : folders) {
1673
                        FolderDTO dto = f.getDTO();
1674
                        dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1675
                        result.add(dto);
1676
                }
1677
                return result;
1678

    
1679
        }
1680

    
1681
        @Override
1682
        public List<FolderDTO> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1683
                if (userId == null)
1684
                        throw new ObjectNotFoundException("No user specified");
1685
                if (folderId == null)
1686
                        throw new ObjectNotFoundException("No folder specified");
1687
                User user = dao.getEntityById(User.class, userId);
1688
                Folder folder = dao.getEntityById(Folder.class, folderId);
1689
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1690
                if (folder.isShared(user))
1691
                        for (Folder f : folder.getSubfolders())
1692
                                if (f.isShared(user) && !f.isDeleted())
1693
                                        result.add(f.getDTO());
1694
                return result;
1695
        }
1696

    
1697
        @Override
1698
        public List<FolderDTO> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1699
                if (userId == null)
1700
                        throw new ObjectNotFoundException("No user specified");
1701
                if (callingUserId == null)
1702
                        throw new ObjectNotFoundException("No user specified");
1703
                if (folderId == null)
1704
                        throw new ObjectNotFoundException("No folder specified");
1705
                User user = dao.getEntityById(User.class, callingUserId);
1706
                Folder folder = dao.getEntityById(Folder.class, folderId);
1707
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1708
                if (folder.isSharedForOtherUser(user))
1709
                        for (Folder f : folder.getSubfolders())
1710
                                if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1711
                                        FolderDTO dto = f.getDTO();
1712
                                        dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId()));
1713
                                        result.add(dto);
1714
                                }
1715
                return result;
1716

    
1717
        }
1718

    
1719
        /* (non-Javadoc)
1720
         * @see gr.ebs.gss.server.ejb.ExternalAPI#searchFiles(java.lang.Long, java.lang.String)
1721
         */
1722
        @Override
1723
        public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1724
                if (userId == null)
1725
                        throw new ObjectNotFoundException("No user specified");
1726
                User user = getUser(userId);
1727
                if (query == null)
1728
                        throw new ObjectNotFoundException("No query specified");
1729
                List<FileHeader> files = search(user.getId(), query);
1730
                List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1731
                for(FileHeader f : files)
1732
                        res.add(f.getDTO());
1733
                return res;
1734
        }
1735

    
1736
        /**
1737
         * Performs the actuals search on the solr server and returns the results
1738
         *
1739
         * We have to use the dismax query type (instead of the
1740
         * standard) because it allows for search time field boosting. This is because we can't use indexing
1741
         * time field boosting due to the patched rich indexing API that does not allow it
1742
         *
1743
         * @param userId
1744
         * @param query
1745
         * @return a List of FileHeader objects
1746
         */
1747
        private List<FileHeader> search(Long userId, String query) {
1748
                try {
1749
                        HttpClient httpClient = new HttpClient();
1750

    
1751
                        GetMethod method = new GetMethod(getConfiguration().getString("solrSelectUrl"));
1752
                        NameValuePair[] params = {new NameValuePair("qt", "dismax"),
1753
                                                                                new NameValuePair("q", query),
1754
                                                                                new NameValuePair("sort", "score desc"),
1755
                                                                                new NameValuePair("indent", "on")};
1756
                        method.setQueryString(params);
1757
                        int retryCount = 0;
1758
                        int statusCode = 0;
1759
                        String response = null;
1760
                        do {
1761
                                statusCode = httpClient.executeMethod(method);
1762
                                logger.debug("HTTP status: " + statusCode);
1763
                                response = method.getResponseBodyAsString();
1764
                                logger.debug(response);
1765
                                retryCount++;
1766
                                if (statusCode != 200 && retryCount < 3)
1767
                                        try {
1768
                                                Thread.sleep(3000); //Give Solr a little time to be available
1769
                                        } catch (InterruptedException e) {
1770
                                        }
1771
                        } while (statusCode != 200 && retryCount < 3);
1772
                        if (statusCode != 200)
1773
                                throw new EJBException("Search query return error:\n" + response);
1774

    
1775
                        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1776
                        DocumentBuilder db = dbf.newDocumentBuilder();
1777
                        Document doc = db.parse(method.getResponseBodyAsStream());
1778
                        method.releaseConnection();
1779

    
1780
                        Node root = doc.getElementsByTagName("response").item(0);
1781
                        Node lst = root.getFirstChild().getNextSibling();
1782
                        Node status = lst.getFirstChild().getNextSibling();
1783
                        if (status.getAttributes().getNamedItem("name").getNodeValue().equals("status") &&
1784
                                status.getTextContent().equals("0")) {
1785
                                List<FileHeader> fileResult = new ArrayList<FileHeader>();
1786
                                Node result = lst.getNextSibling().getNextSibling();
1787
                                NodeList docs = result.getChildNodes();
1788
                                User user = getUser(userId);
1789
                                for (int i=1; i<docs.getLength(); i=i+2) {
1790
                                        Node d = docs.item(i);
1791
                                        NodeList docData = d.getChildNodes();
1792
                                        for (int j=1; j<docData.getLength(); j=j+2) {
1793
                                                Node dd = docData.item(j);
1794
                                                if (dd.getAttributes().item(0).getNodeName().equals("name") &&
1795
                                                        dd.getAttributes().item(0).getNodeValue().equals("id")) {
1796
                                                        Long fileId = Long.valueOf(dd.getTextContent());
1797
                                                        try {
1798
                                                                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1799
                                                                if (file.hasReadPermission(user)) {
1800
                                                                        fileResult.add(file);
1801
                                                                        logger.debug("File added " + fileId);
1802
                                                                }
1803
                                                        } catch (ObjectNotFoundException e) {
1804
                                                                logger.warn("Search result not found", e);
1805
                                                        }
1806
                                                }
1807
                                        }
1808
                                }
1809
                                return fileResult;
1810
                        }
1811
                        throw new EJBException();
1812
                } catch (HttpException e) {
1813
                        throw new EJBException(e);
1814
                } catch (IOException e) {
1815
                        throw new EJBException(e);
1816
                } catch (SAXException e) {
1817
                        throw new EJBException(e);
1818
                } catch (ParserConfigurationException e) {
1819
                        throw new EJBException(e);
1820
                } catch (ObjectNotFoundException e) {
1821
                        throw new EJBException(e);
1822
                }
1823
        }
1824

    
1825
        /* (non-Javadoc)
1826
         * @see gr.ebs.gss.server.ejb.ExternalAPI#copyFiles(java.lang.Long, java.util.List, java.lang.Long)
1827
         */
1828
        @Override
1829
        public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1830
                for(Long l : fileIds){
1831
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1832
                        copyFile(userId, l, destId, file.getName());
1833
                }
1834

    
1835

    
1836
        }
1837

    
1838
        /* (non-Javadoc)
1839
         * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFiles(java.lang.Long, java.util.List, java.lang.Long)
1840
         */
1841
        @Override
1842
        public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1843
                for(Long l : fileIds){
1844
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1845
                        moveFile(userId, l, destId, file.getName());
1846
                }
1847

    
1848
        }
1849

    
1850
        /* (non-Javadoc)
1851
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFiles(java.lang.Long, java.util.List)
1852
         */
1853
        @Override
1854
        public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1855
                if (userId == null)
1856
                        throw new ObjectNotFoundException("No user specified");
1857
                final User user = dao.getEntityById(User.class, userId);
1858
                List<String> filesToRemove = new ArrayList<String>();
1859
                //first delete database objects
1860
                for(Long fileId : fileIds){
1861
                        if (fileId == null)
1862
                                throw new ObjectNotFoundException("No file specified");
1863
                        final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1864
                        final Folder parent = file.getFolder();
1865
                        if (parent == null)
1866
                                throw new ObjectNotFoundException("The specified file has no parent folder");
1867
                        if (!file.hasDeletePermission(user))
1868
                                throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1869

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

    
1883
        }
1884

    
1885
        /* (non-Javadoc)
1886
         * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFilesToTrash(java.lang.Long, java.util.List)
1887
         */
1888
        @Override
1889
        public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1890
                for(Long l : fileIds)
1891
                        moveFileToTrash(userId, l);
1892

    
1893
        }
1894

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

    
1900
        }
1901

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

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

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

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

    
1938
        /* (non-Javadoc)
1939
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserStatistics(java.lang.Long)
1940
         */
1941
        @Override
1942
        public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1943
                if (userId == null)
1944
                        throw new ObjectNotFoundException("No user specified");
1945
                StatsDTO stats = new StatsDTO();
1946
                stats.setFileCount(dao.getFileCount(userId));
1947
                Long fileSize = dao.getFileSize(userId);
1948
                stats.setFileSize(fileSize);
1949
                Long quota = getQuota(userId);
1950
                Long quotaLeft = quota - fileSize;
1951
                stats.setQuotaLeftSize(quotaLeft);
1952
                return stats;
1953
        }
1954

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

    
1974
        /* (non-Javadoc)
1975
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeVersion(java.lang.Long, java.lang.Long, java.lang.Long)
1976
         */
1977
        @Override
1978
        public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
1979
                if (userId == null)
1980
                        throw new ObjectNotFoundException("No user specified");
1981
                if (fileId == null)
1982
                        throw new ObjectNotFoundException("No file specified");
1983
                if (bodyId == null)
1984
                        throw new ObjectNotFoundException("No body specified");
1985
                User user = dao.getEntityById(User.class, userId);
1986
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1987
                if(!header.hasWritePermission(user))
1988
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1989
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
1990
                if(body.equals(header.getCurrentBody())){
1991

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

    
2001
                Folder parent = header.getFolder();
2002
                touchParentFolders(parent, user, new Date());
2003

    
2004
        }
2005

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

    
2019
                try {
2020
                        updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
2021
                } catch (FileNotFoundException e) {
2022
                        throw new GSSIOException(e);
2023
                }
2024

    
2025
        }
2026

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

    
2051
                Folder parent = header.getFolder();
2052
                touchParentFolders(parent, user, new Date());
2053
        }
2054

    
2055
        /* (non-Javadoc)
2056
         * @see gr.ebs.gss.server.ejb.ExternalAPI#toggleFileVersioning(java.lang.Long, java.lang.Long, boolean)
2057
         */
2058
        @Override
2059
        public void toggleFileVersioning(Long userId, Long fileId, boolean versioned) throws ObjectNotFoundException, InsufficientPermissionsException {
2060
                if (userId == null)
2061
                        throw new ObjectNotFoundException("No user specified");
2062
                if (fileId == null)
2063
                        throw new ObjectNotFoundException("No file specified");
2064
                User user = dao.getEntityById(User.class, userId);
2065
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2066
                if(!header.hasWritePermission(user))
2067
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2068
                if(!header.isVersioned() == versioned){
2069
                        if(header.isVersioned())
2070
                                removeOldVersions(userId, fileId);
2071
                        header.setVersioned(versioned);
2072
                        Folder parent = header.getFolder();
2073
                        touchParentFolders(parent, user, new Date());
2074
                }
2075
        }
2076

    
2077
        /**
2078
         * Gets the quota left for specified userId
2079
         * @param userId
2080
         * @return
2081
         */
2082
        private Long getQuotaLeft(Long userId){
2083
                Long fileSize = dao.getFileSize(userId);
2084
                Long quota = getQuota(userId);
2085
                return quota - fileSize;
2086
        }
2087

    
2088
        /**
2089
         * Gets the quota for specified userId
2090
         * @param userId
2091
         * @return
2092
         */
2093
        private Long getQuota(@SuppressWarnings("unused") Long userId){
2094
                Long quota = getConfiguration().getLong("quota", new Long(52428800L));
2095
                return quota;
2096
        }
2097

    
2098
        public void rebuildSolrIndex() {
2099
                MessageProducer sender = null;
2100
                Session session = null;
2101
                Connection qConn = null;
2102
                try {
2103
                        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2104
                        DocumentBuilder db = dbf.newDocumentBuilder();
2105
                        Document doc = db.newDocument();
2106
                        Node root = doc.createElement("delete");
2107
                        doc.appendChild(root);
2108
                        Node queryNode = doc.createElement("query");
2109
                        root.appendChild(queryNode);
2110
                        queryNode.appendChild(doc.createTextNode("*:*"));
2111

    
2112
                        TransformerFactory fact = TransformerFactory.newInstance();
2113
                        Transformer trans = fact.newTransformer();
2114
                        trans.setOutputProperty(OutputKeys.INDENT, "yes");
2115
                        StringWriter sw = new StringWriter();
2116
                        StreamResult sr = new StreamResult(sw);
2117
                        DOMSource source = new DOMSource(doc);
2118
                        trans.transform(source, sr);
2119
                        logger.debug(sw.toString());
2120

    
2121
                        HttpClient httpClient = new HttpClient();
2122
                        PostMethod method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2123
                        method.setRequestEntity(new StringRequestEntity(sw.toString()));
2124
                        int retryCount = 0;
2125
                        int statusCode = 0;
2126
                        String response = null;
2127
                        do {
2128
                                statusCode = httpClient.executeMethod(method);
2129
                                logger.debug("HTTP status: " + statusCode);
2130
                                response = method.getResponseBodyAsString();
2131
                                logger.debug(response);
2132
                                retryCount++;
2133
                                if (statusCode != 200 && retryCount < 3)
2134
                                        try {
2135
                                                Thread.sleep(10000); //Give Solr a little time to be available
2136
                                        } catch (InterruptedException e) {
2137
                                        }
2138
                        } while (statusCode != 200 && retryCount < 3);
2139
                        method.releaseConnection();
2140
                        if (statusCode != 200)
2141
                                throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response);
2142
                        List<Long> fileIds = dao.getAllFileIds();
2143

    
2144
                        Context jndiCtx = new InitialContext();
2145
                        ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
2146
                        Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
2147
                        qConn = factory.createConnection();
2148
                        session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
2149
                        sender = session.createProducer(queue);
2150

    
2151
                        for (Long id : fileIds) {
2152
                                MapMessage map = session.createMapMessage();
2153
                                map.setObject("id", id);
2154
                                map.setBoolean("delete", false);
2155
                                sender.send(map);
2156
                        }
2157
                        sendOptimize(httpClient, 0);
2158
                } catch (DOMException e) {
2159
                        throw new EJBException(e);
2160
                } catch (TransformerConfigurationException e) {
2161
                        throw new EJBException(e);
2162
                } catch (IllegalArgumentException e) {
2163
                        throw new EJBException(e);
2164
                } catch (HttpException e) {
2165
                        throw new EJBException(e);
2166
                } catch (UnsupportedEncodingException e) {
2167
                        throw new EJBException(e);
2168
                } catch (ParserConfigurationException e) {
2169
                        throw new EJBException(e);
2170
                } catch (TransformerException e) {
2171
                        throw new EJBException(e);
2172
                } catch (IOException e) {
2173
                        throw new EJBException(e);
2174
                } catch (NamingException e) {
2175
                        throw new EJBException(e);
2176
                } catch (JMSException e) {
2177
                        throw new EJBException(e);
2178
                }
2179
                finally {
2180
                        try {
2181
                                if (sender != null)
2182
                                        sender.close();
2183
                                if (session != null)
2184
                                        session.close();
2185
                                if (qConn != null)
2186
                                        qConn.close();
2187
                        }
2188
                        catch (JMSException e) {
2189
                                logger.warn(e);
2190
                        }
2191
                }
2192
        }
2193

    
2194
        /**
2195
         * Sends a optimize message to the solr server
2196
         *
2197
         * @param httpClient
2198
         * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive
2199
         *                                         calls to stop the recursion
2200
         * @throws UnsupportedEncodingException
2201
         * @throws IOException
2202
         * @throws HttpException
2203
         */
2204
        private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException {
2205
                PostMethod method = null;
2206
                try {
2207
                        logger.debug("Optimize retry: " + retryCount);
2208
                        method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2209
                        method.setRequestEntity(new StringRequestEntity("<optimize/>", "text/xml", "iso8859-1"));
2210
                        int statusCode = httpClient.executeMethod(method);
2211
                        logger.debug("HTTP status: " + statusCode);
2212
                        String response = method.getResponseBodyAsString();
2213
                        logger.debug(response);
2214
                        if (statusCode != 200 && retryCount < 2) {
2215
                                try {
2216
                                        Thread.sleep(10000); //Give Solr a little time to be available
2217
                                } catch (InterruptedException e) {
2218
                                }
2219
                                sendOptimize(httpClient, retryCount + 1);
2220
                        }
2221
                }
2222
                finally {
2223
                        if (method != null)
2224
                                method.releaseConnection();
2225
                }
2226
        }
2227

    
2228
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2229
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2230
                        InsufficientPermissionsException, QuotaExceededException {
2231
                // Validate.
2232
                if (userId == null)
2233
                        throw new ObjectNotFoundException("No user specified");
2234
                if (folderId == null)
2235
                        throw new ObjectNotFoundException("No folder specified");
2236
                String contentType = mimeType;
2237
                if (StringUtils.isEmpty(mimeType))
2238
                        contentType = DEFAULT_MIME_TYPE;
2239
                if (StringUtils.isEmpty(name))
2240
                        throw new ObjectNotFoundException("No file name specified");
2241
                if (dao.existsFolderOrFile(folderId, name))
2242
                        throw new DuplicateNameException("A folder or file with the name '" + name +
2243
                                                "' already exists at this level");
2244

    
2245
                // Do the actual work.
2246
                Folder parent = null;
2247
                try {
2248
                        parent = dao.getEntityById(Folder.class, folderId);
2249
                } catch (final ObjectNotFoundException onfe) {
2250
                        // Supply a more accurate problem description.
2251
                        throw new ObjectNotFoundException("Parent folder not found");
2252
                }
2253
                final User owner = dao.getEntityById(User.class, userId);
2254
                if (!parent.hasWritePermission(owner))
2255
                        throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2256
                final FileHeader file = new FileHeader();
2257
                file.setName(name);
2258
                parent.addFile(file);
2259
                // set file owner to folder owner
2260
                file.setOwner(parent.getOwner());
2261

    
2262
                final Date now = new Date();
2263
                final AuditInfo auditInfo = new AuditInfo();
2264
                auditInfo.setCreatedBy(owner);
2265
                auditInfo.setCreationDate(now);
2266
                auditInfo.setModifiedBy(owner);
2267
                auditInfo.setModificationDate(now);
2268
                file.setAuditInfo(auditInfo);
2269
                // TODO set the proper versioning flag on creation
2270
                file.setVersioned(false);
2271

    
2272
                for (final Permission p : parent.getPermissions()) {
2273
                        final Permission permission = new Permission();
2274
                        permission.setGroup(p.getGroup());
2275
                        permission.setUser(p.getUser());
2276
                        permission.setRead(p.getRead());
2277
                        permission.setWrite(p.getWrite());
2278
                        permission.setModifyACL(p.getModifyACL());
2279
                        file.addPermission(permission);
2280
                }
2281

    
2282
                // Create the file body.
2283
                try {
2284
                        createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2285
                } catch (FileNotFoundException e) {
2286
                        throw new GSSIOException(e);
2287
                }
2288
                touchParentFolders(parent, owner, new Date());
2289
                dao.flush();
2290
                indexFile(file.getId(), false);
2291

    
2292
                return file.getDTO();
2293
        }
2294

    
2295
        /* (non-Javadoc)
2296
         * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFileContents(java.lang.Long, java.lang.Long, java.lang.String, java.io.InputStream)
2297
         */
2298
        public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2299
                if (userId == null)
2300
                        throw new ObjectNotFoundException("No user specified");
2301
                if (fileId == null)
2302
                        throw new ObjectNotFoundException("No file specified");
2303
                String contentType = mimeType;
2304

    
2305
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2306

    
2307
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2308
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2309
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2310
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2311
                        contentType = identifyMimeType(file.getName());
2312

    
2313
                final User owner = dao.getEntityById(User.class, userId);
2314
                if (!file.hasWritePermission(owner))
2315
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2316
                final Date now = new Date();
2317
                final AuditInfo auditInfo = new AuditInfo();
2318
                auditInfo.setCreatedBy(owner);
2319
                auditInfo.setCreationDate(now);
2320
                auditInfo.setModifiedBy(owner);
2321
                auditInfo.setModificationDate(now);
2322
                try {
2323
                        createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2324
                } catch (FileNotFoundException e) {
2325
                        throw new GSSIOException(e);
2326
                }
2327
                Folder parent = file.getFolder();
2328
                touchParentFolders(parent, owner, new Date());
2329

    
2330
                indexFile(fileId, false);
2331
                return file.getDTO();
2332
        }
2333

    
2334
        /**
2335
         * Helper method for identifying mime type by examining the filename extension
2336
         *
2337
         * @param filename
2338
         * @return the mime type
2339
         */
2340
        private String identifyMimeType(String filename) {
2341
                if (filename.indexOf('.') != -1) {
2342
                        String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2343
                        if (".doc".equals(extension))
2344
                                return "application/msword";
2345
                        else if (".xls".equals(extension))
2346
                                return "application/vnd.ms-excel";
2347
                        else if (".ppt".equals(extension))
2348
                                return "application/vnd.ms-powerpoint";
2349
                        else if (".pdf".equals(extension))
2350
                                return "application/pdf";
2351
                        else if (".gif".equals(extension))
2352
                                return "image/gif";
2353
                        else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2354
                                return "image/jpeg";
2355
                        else if (".tiff".equals(extension) || ".tif".equals(extension))
2356
                                return "image/tiff";
2357
                        else if (".png".equals(extension))
2358
                                return "image/png";
2359
                        else if (".bmp".equals(extension))
2360
                                return "image/bmp";
2361
                }
2362
                // when all else fails assign the default mime type
2363
                return DEFAULT_MIME_TYPE;
2364
        }
2365

    
2366
        /**
2367
         * Helper method to create a new file body and attach it as the current body
2368
         * of the provided file header.
2369
         *
2370
         * @param name the original file name
2371
         * @param mimeType the content type
2372
         * @param fileSize the uploaded file size
2373
         * @param filePath the uploaded file full path
2374
         * @param header the file header that will be associated with the new body
2375
         * @param auditInfo the audit info
2376
         * @param owner the owner of the file
2377
         * @throws FileNotFoundException
2378
         * @throws QuotaExceededException
2379
         */
2380
        private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2381
                                FileHeader header, AuditInfo auditInfo)
2382
                        throws FileNotFoundException, QuotaExceededException {
2383

    
2384
                long currentTotalSize = 0;
2385
                if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2386
                        currentTotalSize = header.getTotalSize();
2387
                Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2388
                if(quotaLeft < fileSize-currentTotalSize) {
2389
                        // quota exceeded -> delete the file
2390
                        deleteActualFile(filePath);
2391
                        throw new QuotaExceededException("Not enough free space available");
2392
                }
2393

    
2394
                FileBody body = new FileBody();
2395

    
2396
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2397
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2398
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2399
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2400
                        body.setMimeType(identifyMimeType(name));
2401
                else
2402
                        body.setMimeType(mimeType);
2403
                body.setAuditInfo(auditInfo);
2404
                body.setFileSize(fileSize);
2405
                body.setOriginalFilename(name);
2406
                body.setStoredFilePath(filePath);
2407
                //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2408
                if(!header.isVersioned() && header.getCurrentBody() != null){
2409
                        header.setCurrentBody(null);
2410
                        if (header.getBodies() != null) {
2411
                                Iterator<FileBody> it = header.getBodies().iterator();
2412
                                while(it.hasNext()){
2413
                                        FileBody bo = it.next();
2414
                                        deleteActualFile(bo.getStoredFilePath());
2415
                                        it.remove();
2416
                                        dao.delete(bo);
2417
                                }
2418
                        }
2419
                }
2420

    
2421
                dao.flush();
2422
                header.addBody(body);
2423
                header.setAuditInfo(auditInfo);
2424

    
2425
                dao.create(body);
2426
        }
2427

    
2428

    
2429
        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2430
        public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2431
                if (userId == null)
2432
                        throw new ObjectNotFoundException("No user specified");
2433
                User owner = dao.getEntityById(User.class, userId);
2434
                if(owner == null)
2435
                        throw new ObjectNotFoundException("No user specified");
2436
                long start = 0, end = 0;
2437
                if (logger.isDebugEnabled())
2438
                        start = System.currentTimeMillis();
2439
                File result = new File(generateRepositoryFilePath());
2440
                try {
2441
                        final FileOutputStream output = new FileOutputStream(result);
2442
                        final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2443
                        int n = 0;
2444

    
2445
                        while (-1 != (n = stream.read(buffer)))
2446
                                output.write(buffer, 0, n);
2447
                        output.close();
2448
                        stream.close();
2449
                } catch (IOException e) {
2450
                        if (!result.delete())
2451
                                logger.warn("Could not delete " + result.getPath());
2452
                        throw e;
2453
                }
2454
                if (logger.isDebugEnabled()) {
2455
                        end = System.currentTimeMillis();
2456
                        logger.debug("Time to upload: " + (end - start) + " (msec)");
2457
                }
2458
                return result;
2459
        }
2460

    
2461

    
2462
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2463

    
2464
                if (userId == null)
2465
                        throw new ObjectNotFoundException("No user specified");
2466
                User user = dao.getEntityById(User.class, userId);
2467
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2468
                if(status == null){
2469
                        status = new FileUploadStatus();
2470
                        status.setOwner(user);
2471
                        status.setFilename(filename);
2472
                        status.setBytesUploaded(bytesTransfered);
2473
                        status.setFileSize(fileSize);
2474
                        dao.create(status);
2475
                }
2476
                else{
2477
                        status.setBytesUploaded(bytesTransfered);
2478
                        status.setFileSize(fileSize);
2479
                        dao.update(status);
2480
                }
2481

    
2482
        }
2483

    
2484
        public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2485
                if (userId == null)
2486
                        throw new ObjectNotFoundException("No user specified");
2487
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2488
                if(status != null)
2489
                        dao.delete(status);
2490
        }
2491

    
2492
        @Override
2493
        public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2494
                return dao.getFileUploadStatus(userId, fileName);
2495
        }
2496

    
2497
        @Override
2498
        public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2499
                if (userId == null)
2500
                        throw new ObjectNotFoundException("No user specified");
2501
                if (folderId == null)
2502
                        throw new ObjectNotFoundException("No folder specified");
2503
                final User user = dao.getEntityById(User.class, userId);
2504
                final Folder folder = dao.getEntityById(Folder.class, folderId);
2505
                // Check permissions
2506
                if (!folder.hasReadPermission(user))
2507
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2508
                List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2509
                if (folder.hasReadPermission(user))
2510
                        for (Folder f : folder.getSubfolders())
2511
                                if (f.hasReadPermission(user) && !f.isDeleted())
2512
                                        subfolders.add(f.getDTO());
2513
                FolderDTO result = folder.getDTO();
2514
                result.setSubfolders(subfolders);
2515
                return folder.getDTO();
2516
        }
2517

    
2518
        @Override
2519
        public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2520
                if (userId == null)
2521
                        throw new ObjectNotFoundException("No user specified");
2522
                if (folderId == null)
2523
                        throw new ObjectNotFoundException("No folder specified");
2524
                User user = dao.getEntityById(User.class, callingUserId);
2525
                Folder folder = dao.getEntityById(Folder.class, folderId);
2526
                // Check permissions
2527
                if (!folder.hasReadPermission(user))
2528
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2529

    
2530
                FolderDTO result = folder.getDTO();
2531
                result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2532
                return result;
2533
        }
2534

    
2535
        @Override
2536
        public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2537
                        throws ObjectNotFoundException, InsufficientPermissionsException {
2538
                if (userId == null)
2539
                        throw new ObjectNotFoundException("No user specified");
2540
                if (fileId == null)
2541
                        throw new ObjectNotFoundException("No file specified");
2542
                if (version < 1)
2543
                        throw new ObjectNotFoundException("No valid version specified");
2544
                User user = dao.getEntityById(User.class, userId);
2545
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2546
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2547
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2548
                FileBody body = dao.getFileVersion(fileId, version);
2549
                return body.getDTO();
2550
        }
2551

    
2552
        @Override
2553
        public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2554
                if (userId == null)
2555
                        throw new ObjectNotFoundException("No user specified");
2556
                User user = dao.getEntityById(User.class, userId);
2557
                user.setAcceptedPolicy(isAccepted);
2558
                return user;
2559
        }
2560

    
2561
        @Override
2562
        public void updateAccounting(User user, Date date, long bandwidthDiff) {
2563
                dao.updateAccounting(user, date, bandwidthDiff);
2564
        }
2565

    
2566
        @Override
2567
        public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2568
                if (userId == null)
2569
                        throw new ObjectNotFoundException("No user specified");
2570
                if (folderId == null)
2571
                        throw new ObjectNotFoundException("No folder specified");
2572
                User user = dao.getEntityById(User.class, userId);
2573
                Folder folder = dao.getEntityById(Folder.class, folderId);
2574
                // Check permissions
2575
                if (!folder.hasReadPermission(user))
2576
                        return false;
2577
                return true;
2578
        }
2579

    
2580
        /**
2581
         * Reset WebDAV password for given user.
2582
         *
2583
         * @param userId
2584
         * @return the new password
2585
         * @throws ObjectNotFoundException
2586
         */
2587
        @Override
2588
        public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2589
                if (userId == null)
2590
                        throw new ObjectNotFoundException("No user specified");
2591
                User user = dao.getEntityById(User.class, userId);
2592
                user.generateWebDAVPassword();
2593
                return user.getWebDAVPassword();
2594
        }
2595

    
2596
}