Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (94.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
        @Override
143
        public FolderDTO getRootFolder(Long userId) throws ObjectNotFoundException {
144
                if (userId == null)
145
                        throw new ObjectNotFoundException("No user specified");
146
                Folder folder = dao.getRootFolder(userId);
147
                return folder.getDTO();
148
        }
149

    
150
        /*
151
         * (non-Javadoc)
152
         *
153
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolder(java.lang.Long)
154
         */
155
        public FolderDTO getFolder(final Long userId, final Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
156
                if (userId == null)
157
                        throw new ObjectNotFoundException("No user specified");
158
                if (folderId == null)
159
                        throw new ObjectNotFoundException("No folder specified");
160
                final User user = dao.getEntityById(User.class, userId);
161
                final Folder folder = dao.getEntityById(Folder.class, folderId);
162
                // Check permissions
163
                if (!folder.hasReadPermission(user))
164
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
165
                return folder.getDTO();
166
        }
167

    
168
        /* (non-Javadoc)
169
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUser(java.lang.Long)
170
         */
171
        public User getUser(Long userId) throws ObjectNotFoundException {
172
                if (userId == null)
173
                        throw new ObjectNotFoundException("No user specified");
174
                return dao.getEntityById(User.class, userId);
175
        }
176

    
177
        /* (non-Javadoc)
178
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserDTO(java.lang.Long)
179
         */
180
        public UserDTO getUserDTO(final Long userId) throws ObjectNotFoundException {
181
                return getUser(userId).getDTO();
182
        }
183

    
184
        /*
185
         * (non-Javadoc)
186
         *
187
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroup(java.lang.Long)
188
         */
189
        public GroupDTO getGroup(final Long groupId) throws ObjectNotFoundException {
190
                if (groupId == null)
191
                        throw new ObjectNotFoundException("No group specified");
192
                final Group group = dao.getEntityById(Group.class, groupId);
193
                return group.getDTO();
194
        }
195

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

    
210
        /*
211
         * (non-Javadoc)
212
         *
213
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getGroups(java.lang.Long)
214
         */
215
        public List<GroupDTO> getGroups(final Long userId) throws ObjectNotFoundException {
216
                if (userId == null)
217
                        throw new ObjectNotFoundException("No user specified");
218
                final List<Group> groups = dao.getGroups(userId);
219
                final List<GroupDTO> result = new ArrayList<GroupDTO>();
220
                for (final Group g : groups)
221
                        result.add(g.getDTO());
222
                return result;
223
        }
224

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

    
245
        /*
246
         * (non-Javadoc)
247
         *
248
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsers(java.lang.Long,
249
         *      java.lang.Long)
250
         */
251
        public List<UserDTO> getUsers(final Long userId, final Long groupId) throws ObjectNotFoundException {
252
                // Validate.
253
                if (userId == null)
254
                        throw new ObjectNotFoundException("No user specified");
255
                if (groupId == null)
256
                        throw new ObjectNotFoundException("No group specified");
257

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

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

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

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

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

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

    
313
                Date now = new Date();
314
                AuditInfo auditInfo = new AuditInfo();
315
                auditInfo.setCreatedBy(creator);
316
                auditInfo.setCreationDate(now);
317
                auditInfo.setModifiedBy(creator);
318
                auditInfo.setModificationDate(now);
319
                folder.setAuditInfo(auditInfo);
320

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

    
342
        /*
343
         * Deletes the given folder and all its subfolders and files
344
         * Only the permissions for top folder are checked
345
         *
346
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFolder(java.lang.Long,
347
         *      java.lang.Long)
348
         */
349
        public void deleteFolder(final Long userId, final Long folderId) throws InsufficientPermissionsException, ObjectNotFoundException {
350
                // Validate.
351
                if (userId == null)
352
                        throw new ObjectNotFoundException("No user specified");
353
                if (folderId == null)
354
                        throw new ObjectNotFoundException("No folder specified");
355

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

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

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

    
408
        @Override
409
        public FolderDTO modifyFolder(Long userId, Long folderId, String folderName)
410
                        throws InsufficientPermissionsException, ObjectNotFoundException, DuplicateNameException {
411

    
412
                // Validate.
413
                if (userId == null)
414
                        throw new ObjectNotFoundException("No user specified");
415
                if (folderId == null)
416
                        throw new ObjectNotFoundException("No folder specified");
417
                if (StringUtils.isEmpty(folderName))
418
                        throw new ObjectNotFoundException("New folder name is empty");
419

    
420
                Folder folder = dao.getEntityById(Folder.class, folderId);
421
                User user = dao.getEntityById(User.class, userId);
422
                if (!folder.hasWritePermission(user))
423
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
424

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

    
430
                // Do the actual modification.
431
                folder.setName(folderName);
432
                dao.update(folder);
433
                return folder.getDTO();
434
        }
435

    
436
        /*
437
         * (non-Javadoc)
438
         *
439
         * @see gr.ebs.gss.server.ejb.ExternalAPI#createGroup(java.lang.Long,
440
         *      java.lang.String)
441
         */
442
        public void createGroup(final Long userId, final String name) throws ObjectNotFoundException, DuplicateNameException {
443
                // Validate.
444
                if (userId == null)
445
                        throw new ObjectNotFoundException("No user specified");
446
                if (StringUtils.isEmpty(name))
447
                        throw new ObjectNotFoundException("New group name is empty");
448
                if (dao.existsGroup(userId, name))
449
                        throw new DuplicateNameException("A group with the name '" + name + "' already exists");
450

    
451
                // TODO: Check permissions
452

    
453
                final User owner = dao.getEntityById(User.class, userId);
454

    
455
                // Do the actual work.
456
                owner.createGroup(name);
457
        }
458

    
459
        /*
460
         * (non-Javadoc)
461
         *
462
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteGroup(java.lang.Long,
463
         *      java.lang.Long)
464
         */
465
        public void deleteGroup(final Long userId, final Long groupId) throws ObjectNotFoundException, InsufficientPermissionsException {
466
                // Validate.
467
                if (userId == null)
468
                        throw new ObjectNotFoundException("No user specified");
469
                if (groupId == null)
470
                        throw new ObjectNotFoundException("No group specified");
471

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

    
492
        @Override
493
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, InputStream stream)
494
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
495
                        InsufficientPermissionsException, QuotaExceededException {
496
                File file = null;
497
                try {
498
                        file = uploadFile(stream, userId);
499
                } catch ( IOException ioe) {
500
                        // Supply a more accurate problem description.
501
                        throw new GSSIOException("Problem creating file",ioe);
502
                }
503
                return createFile(userId, folderId, name, mimeType, file.length(), file.getAbsolutePath());
504
        }
505

    
506
        /* (non-Javadoc)
507
         * @see gr.ebs.gss.server.ejb.ExternalAPIRemote#indexFile(java.lang.Long, boolean)
508
         */
509
        public void indexFile(Long fileId, boolean delete) {
510
                Connection qConn = null;
511
                Session session = null;
512
                MessageProducer sender = null;
513
                try {
514
                        Context jndiCtx = new InitialContext();
515
                        ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
516
                        Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
517
                        qConn = factory.createConnection();
518
                        session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
519
                        sender = session.createProducer(queue);
520

    
521
                        MapMessage map = session.createMapMessage();
522
                        map.setObject("id", fileId);
523
                        map.setBoolean("delete", delete);
524
                        sender.send(map);
525
                }
526
                catch (NamingException e) {
527
                        logger.error("Index was not updated: ", e);
528
                }
529
                catch (JMSException e) {
530
                        logger.error("Index was not updated: ", e);
531
                }
532
                finally {
533
                        try {
534
                                if (sender != null)
535
                                        sender.close();
536
                                if (session != null)
537
                                        session.close();
538
                                if (qConn != null)
539
                                        qConn.close();
540
                        }
541
                        catch (JMSException e) {
542
                                logger.warn(e);
543
                        }
544
                }
545
        }
546

    
547

    
548

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

    
574
        /*
575
         * (non-Javadoc)
576
         *
577
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFile(java.lang.Long,
578
         *      java.lang.Long)
579
         */
580
        public void deleteFile(final Long userId, final Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
581
                // Validate.
582
                if (userId == null)
583
                        throw new ObjectNotFoundException("No user specified");
584
                if (fileId == null)
585
                        throw new ObjectNotFoundException("No file specified");
586

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

    
601
        private void deleteActualFile(String filePath) {
602
                if (filePath == null)
603
                        return;
604
                File file = new File(filePath);
605
                if (!file.delete())
606
                        logger.error("Could not delete file " + filePath);
607
        }
608

    
609
        /*
610
         * (non-Javadoc)
611
         *
612
         * @see gr.ebs.gss.server.ejb.ExternalAPI#createTag(java.lang.Long,
613
         *      java.lang.Long, java.lang.String)
614
         */
615
        public void createTag(final Long userId, final Long fileHeaderId, final String tag) throws ObjectNotFoundException {
616
                if (userId == null)
617
                        throw new ObjectNotFoundException("No user specified");
618
                if (fileHeaderId == null)
619
                        throw new ObjectNotFoundException("No file specified");
620
                if (StringUtils.isEmpty(tag))
621
                        throw new ObjectNotFoundException("Tag is empty");
622

    
623
                final User user = dao.getEntityById(User.class, userId);
624
                final FileHeader fh = dao.getEntityById(FileHeader.class, fileHeaderId);
625
                user.addTag(fh, tag);
626
        }
627

    
628
        /* (non-Javadoc)
629
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserTags(java.lang.Long)
630
         */
631
        @WebMethod(operationName = "getUserTags")
632
        public Set<String> getUserTags(final Long userId) throws ObjectNotFoundException {
633
                return dao.getUserTags(userId);
634
        }
635

    
636
        /* (non-Javadoc)
637
         * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFile(java.lang.Long, java.lang.Long, java.lang.String, java.util.Set)
638
         */
639
        public void updateFile(Long userId, Long fileId, String name, String tagSet) throws ObjectNotFoundException, InsufficientPermissionsException {
640
                if (userId == null)
641
                        throw new ObjectNotFoundException("No user specified");
642
                if (fileId == null)
643
                        throw new ObjectNotFoundException("No file specified");
644
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
645
                User user = dao.getEntityById(User.class, userId);
646
                if (!file.hasWritePermission(user))
647
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot update file " + file.getName() + "(" + file.getId() + ")");
648

    
649
                if (name != null)
650
                        file.setName(name);
651
                List<FileTag> tags = file.getFileTags();
652

    
653
                if (tagSet != null) {
654
                        Iterator<FileTag> i = tags.iterator();
655
                        while (i.hasNext()) {
656
                                FileTag tag = i.next();
657
                                i.remove();
658
                                tag.setFile(null);
659
                                user.removeTag(tag);
660
                                dao.delete(tag);
661
                        }
662
                        dao.flush();
663
                        StringTokenizer st = new StringTokenizer(tagSet, ",");
664
                        while (st.hasMoreTokens())
665
                                new FileTag(user, file, st.nextToken().trim());
666
                }
667

    
668
                // Re-index the file if it was modified.
669
                if (name != null || tagSet != null)
670
                        indexFile(fileId, false);
671
        }
672

    
673
        @Override
674
        public InputStream getFileContents(Long userId, Long fileId)
675
                        throws ObjectNotFoundException, InsufficientPermissionsException {
676
                if (userId == null)
677
                        throw new ObjectNotFoundException("No user specified");
678
                if (fileId == null)
679
                        throw new ObjectNotFoundException("No file specified");
680

    
681
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
682
                User user = dao.getEntityById(User.class, userId);
683
                if (!header.hasReadPermission(user)) {
684
                        logger.info("User " + user.getId() + " cannot read file " + header.getName() + "(" + fileId + ")");
685
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
686
                }
687

    
688
                File f = new File(header.getCurrentBody().getStoredFilePath());
689
                try {
690
                        return new FileInputStream(f);
691
                } catch (FileNotFoundException e) {
692
                        logger.error("Could not locate the contents of file " + f.getAbsolutePath());
693
                        throw new ObjectNotFoundException("The file contents could not be located");
694
                }
695
        }
696

    
697
        /* (non-Javadoc)
698
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFileContents(java.lang.Long, java.lang.Long, java.lang.Long)
699
         */
700
        public InputStream getFileContents(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
701
                if (userId == null)
702
                        throw new ObjectNotFoundException("No user specified");
703
                if (fileId == null)
704
                        throw new ObjectNotFoundException("No file specified");
705
                if (bodyId == null)
706
                        throw new ObjectNotFoundException("No file specified");
707

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

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

    
725
        /* (non-Javadoc)
726
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFile(java.lang.Long, java.lang.Long)
727
         */
728
        public FileHeaderDTO getFile(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
729
                if (userId == null)
730
                        throw new ObjectNotFoundException("No user specified");
731
                if (fileId == null)
732
                        throw new ObjectNotFoundException("No file specified");
733
                final User user = dao.getEntityById(User.class, userId);
734
                final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
735
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
736
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
737
                return file.getDTO();
738
        }
739

    
740
        @Override
741
        public FileBodyDTO getFileBody(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
742
                if (userId == null)
743
                        throw new ObjectNotFoundException("No user specified");
744
                if (fileId == null)
745
                        throw new ObjectNotFoundException("No file specified");
746
                User user = dao.getEntityById(User.class, userId);
747
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
748
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
749
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
750
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
751
                return body.getDTO();
752
        }
753

    
754
        @Override
755
        public Object getResourceAtPath(Long ownerId, String path, boolean ignoreDeleted)
756
                        throws ObjectNotFoundException {
757
                if (ownerId == null)
758
                        throw new ObjectNotFoundException("No user specified");
759
                if (StringUtils.isEmpty(path))
760
                        throw new ObjectNotFoundException("No path specified");
761

    
762
                User owner = dao.getEntityById(User.class, ownerId);
763
                List<String> pathElements = new ArrayList<String>();
764
                StringTokenizer st = new StringTokenizer(path, "/");
765
                while (st.hasMoreTokens())
766
                        pathElements.add(st.nextToken());
767
                if (pathElements.size() < 1)
768
                        return getRootFolder(owner.getId());
769
                // Store the last element, since it requires special handling.
770
                String lastElement = pathElements.remove(pathElements.size() - 1);
771
                FolderDTO cursor = getRootFolder(owner.getId());
772
                // Traverse and verify the specified folder path.
773
                for (String pathElement : pathElements) {
774
                        cursor = getFolder(cursor.getId(), pathElement);
775
                        if (cursor.isDeleted())
776
                                throw new ObjectNotFoundException("Folder " + cursor.getPath() + " not found");
777
                }
778

    
779
                // Use the lastElement to retrieve the actual resource.
780
                Object resource = null;
781
                try {
782
                        FileHeaderDTO file = getFile(cursor.getId(), lastElement);
783
                        if (ignoreDeleted && file.isDeleted())
784
                                throw new ObjectNotFoundException("Resource not found");
785
                        resource = file;
786
                } catch (ObjectNotFoundException e) {
787
                        // Perhaps the requested resource is not a file, so
788
                        // check for folders as well.
789
                        FolderDTO folder = getFolder(cursor.getId(), lastElement);
790
                        if (ignoreDeleted && folder.isDeleted())
791
                                throw new ObjectNotFoundException("Resource not found");
792
                        resource = folder;
793
                }
794
                return resource;
795
        }
796

    
797
        /**
798
         * Retrieve a file for the specified user that has the specified name and
799
         * its parent folder has id equal to folderId.
800
         *
801
         * @param userId the ID of the current user
802
         * @param folderId the ID of the parent folder
803
         * @param name the name of the requested file
804
         * @return the file found
805
         * @throws ObjectNotFoundException if the specified folder or file was not
806
         *             found, with the exception message mentioning the precise
807
         *             problem
808
         */
809
        private FileHeaderDTO getFile(Long folderId, String name) throws ObjectNotFoundException {
810
                if (folderId == null)
811
                        throw new ObjectNotFoundException("No parent folder specified");
812
                if (StringUtils.isEmpty(name))
813
                        throw new ObjectNotFoundException("No file specified");
814

    
815
                FileHeader file = dao.getFile(folderId, name);
816
                return file.getDTO();
817
        }
818

    
819
        /**
820
         * Retrieve a folder for the specified user that has the specified name and
821
         * its parent folder has id equal to parentId.
822
         *
823
         * @param parentId the ID of the parent folder
824
         * @param name the name of the requested folder
825
         * @return the folder found
826
         * @throws ObjectNotFoundException if the specified folder or parent was not
827
         *             found, with the exception message mentioning the precise
828
         *             problem
829
         */
830
        private FolderDTO getFolder(Long parentId, String name) throws ObjectNotFoundException {
831
                if (parentId == null)
832
                        throw new ObjectNotFoundException("No parent folder specified");
833
                if (StringUtils.isEmpty(name))
834
                        throw new ObjectNotFoundException("No folder specified");
835

    
836
                Folder folder = dao.getFolder(parentId, name);
837
                return folder.getDTO();
838
        }
839

    
840
        private FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, InputStream resourceInputStream) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
841
                File file = null;
842
                try {
843
                        file = uploadFile(resourceInputStream, userId);
844
                } catch ( IOException ioe) {
845
                        // Supply a more accurate problem description.
846
                        throw new GSSIOException("Problem creating file",ioe);
847
                }
848
                return updateFileContents(userId, fileId, mimeType, file.length(), file.getAbsolutePath());
849
        }
850

    
851
        @Override
852
        public void copyFile(Long userId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
853
                if (userId == null)
854
                        throw new ObjectNotFoundException("No user specified");
855
                if (fileId == null)
856
                        throw new ObjectNotFoundException("No file specified");
857
                if (StringUtils.isEmpty(dest))
858
                        throw new ObjectNotFoundException("No destination specified");
859

    
860
                Object destination = getResourceAtPath(userId, getParentPath(dest), true);
861
                if (!(destination instanceof FolderDTO))
862
                        throw new ObjectNotFoundException("Destination parent folder not found");
863
                FolderDTO parent = (FolderDTO) destination;
864
                copyFile(userId, fileId, parent.getId(), getLastElement(dest));
865
        }
866

    
867
        @Override
868
        public void copyFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
869
                if (userId == null)
870
                        throw new ObjectNotFoundException("No user specified");
871
                if (ownerId == null)
872
                        throw new ObjectNotFoundException("No owner specified");
873
                if (fileId == null)
874
                        throw new ObjectNotFoundException("No file specified");
875
                if (StringUtils.isEmpty(dest))
876
                        throw new ObjectNotFoundException("No destination specified");
877

    
878
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
879
                if (!(destination instanceof FolderDTO))
880
                        throw new ObjectNotFoundException("Destination parent folder not found");
881
                FolderDTO parent = (FolderDTO) destination;
882
                copyFile(userId, fileId, parent.getId(), getLastElement(dest));
883
        }
884

    
885
        @Override
886
        public void copyFile(Long userId, Long fileId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
887
                if (userId == null)
888
                        throw new ObjectNotFoundException("No user specified");
889
                if (fileId == null)
890
                        throw new ObjectNotFoundException("No file specified");
891
                if (destId == null)
892
                        throw new ObjectNotFoundException("No destination specified");
893
                if (StringUtils.isEmpty(destName))
894
                        throw new ObjectNotFoundException("No destination file name specified");
895

    
896
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
897
                Folder destination = dao.getEntityById(Folder.class, destId);
898
                User user = dao.getEntityById(User.class, userId);
899
                if (!file.hasReadPermission(user) || !destination.hasWritePermission(user))
900
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
901
                boolean versioned = file.isVersioned();
902
                int versionsNumber = file.getBodies().size();
903
                FileBody oldestBody = file.getBodies().get(0);
904
                assert oldestBody != null;
905
                File contents = new File(oldestBody.getStoredFilePath());
906
                try {
907
                        createFile(user.getId(), destination.getId(), destName, oldestBody.getMimeType(), new FileInputStream(contents));
908
                        FileHeader copiedFile = dao.getFile(destination.getId(), destName);
909
                        copiedFile.setVersioned(versioned);
910
                        dao.flush();
911
                        if (versionsNumber > 1)
912
                                for (int i = 1; i < versionsNumber; i++) {
913
                                        FileBody body = file.getBodies().get(i);
914
                                        assert body != null;
915
                                        contents = new File(body.getStoredFilePath());
916
                                        updateFileContents(user.getId(), copiedFile.getId(), body.getMimeType(), new FileInputStream(contents));
917
                                }
918
                        List<FileTag> tags = file.getFileTags();
919
                        for (FileTag tag : tags)
920
                                createTag(userId, copiedFile.getId(), tag.getTag());
921

    
922
                } catch (FileNotFoundException e) {
923
                        throw new ObjectNotFoundException("File contents not found for file " + contents.getAbsolutePath());
924
                }
925

    
926
        }
927

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

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

    
944
        @Override
945
        public void copyFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
946
                if (userId == null)
947
                        throw new ObjectNotFoundException("No user specified");
948
                if (folderId == null)
949
                        throw new ObjectNotFoundException("No folder specified");
950
                if (destId == null)
951
                        throw new ObjectNotFoundException("No destination specified");
952
                if (StringUtils.isEmpty(destName))
953
                        throw new ObjectNotFoundException("No destination folder name specified");
954
                Folder folder = dao.getEntityById(Folder.class, folderId);
955
                Folder destination = dao.getEntityById(Folder.class, destId);
956
                User user = dao.getEntityById(User.class, userId);
957
                if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
958
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
959
                createFolder(user.getId(), destination.getId(), destName);
960
        }
961

    
962
        @Override
963
        public void copyFolderStructureToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
964
                if (userId == null)
965
                        throw new ObjectNotFoundException("No user specified");
966
                if (ownerId == null)
967
                        throw new ObjectNotFoundException("No owner specified");
968
                if (folderId == null)
969
                        throw new ObjectNotFoundException("No folder specified");
970
                if (StringUtils.isEmpty(dest))
971
                        throw new ObjectNotFoundException("No destination specified");
972

    
973
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
974
                if (!(destination instanceof FolderDTO))
975
                        throw new ObjectNotFoundException("Destination folder not found");
976
                FolderDTO parent = (FolderDTO) destination;
977
                copyFolderStructure(userId, folderId, parent.getId(), getLastElement(dest));
978
        }
979

    
980
        @Override
981
        public void copyFolderStructure(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
982
                if (userId == null)
983
                        throw new ObjectNotFoundException("No user specified");
984
                if (folderId == null)
985
                        throw new ObjectNotFoundException("No folder specified");
986
                if (destId == null)
987
                        throw new ObjectNotFoundException("No destination specified");
988
                if (StringUtils.isEmpty(destName))
989
                        throw new ObjectNotFoundException("No destination folder name specified");
990

    
991
                Folder folder = dao.getEntityById(Folder.class, folderId);
992
                Folder destination = dao.getEntityById(Folder.class, destId);
993
                final User user = dao.getEntityById(User.class, userId);
994
                // XXX: quick fix need to copy only visible items to user (Source
995
                // for bugs)
996
                if (!folder.getOwner().getId().equals(userId) && !folder.hasReadPermission(user))
997
                        return;
998
                if(folder.isDeleted())//do not copy trashed folder and contents
999
                        return;
1000
                if (!destination.hasWritePermission(user) || !folder.hasReadPermission(user))
1001
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1002
                createFolder(user.getId(), destination.getId(), destName);
1003
                Folder createdFolder = dao.getFolder(destination.getId(), destName);
1004
                List<FileHeader> files = folder.getFiles();
1005
                if (files != null)
1006
                        for (FileHeader file : files)
1007
                                if(!file.isDeleted())
1008
                                        copyFile(userId, file.getId(), createdFolder.getId(), file.getName());
1009
                List<Folder> subFolders = folder.getSubfolders();
1010
                if (subFolders != null)
1011
                        for (Folder sub : subFolders)
1012
                                if(!sub.getId().equals(createdFolder.getId()))
1013
                                        copyFolderStructure(userId, sub.getId(), createdFolder.getId(), sub.getName());
1014

    
1015
        }
1016

    
1017
        /**
1018
         * For a provided path, remove the last element and return the rest, that is
1019
         * the path of the parent folder.
1020
         *
1021
         * @param path the specified path
1022
         * @return the path of the parent folder
1023
         * @throws ObjectNotFoundException if the provided string contains no path
1024
         *             delimiters
1025
         */
1026
        private String getParentPath(String path) throws ObjectNotFoundException {
1027
                int lastDelimiter = path.lastIndexOf('/');
1028
                if (lastDelimiter == 0)
1029
                        return "/";
1030
                if (lastDelimiter == -1)
1031
                        // No path found.
1032
                        throw new ObjectNotFoundException("There is no parent in the path: " + path);
1033
                else if (lastDelimiter < path.length() - 1)
1034
                        // Return the part before the delimiter.
1035
                        return path.substring(0, lastDelimiter);
1036
                else {
1037
                        // Remove the trailing delimiter and then recurse.
1038
                        String strippedTrail = path.substring(0, lastDelimiter);
1039
                        return getParentPath(strippedTrail);
1040
                }
1041
        }
1042

    
1043
        /**
1044
         * Get the last element in a path that denotes the file or folder name.
1045
         *
1046
         * @param path the provided path
1047
         * @return the last element in the path
1048
         */
1049
        private String getLastElement(String path) {
1050
                int lastDelimiter = path.lastIndexOf('/');
1051
                if (lastDelimiter == -1)
1052
                        // No path found.
1053
                        return path;
1054
                else if (lastDelimiter < path.length() - 1)
1055
                        // Return the part after the delimiter.
1056
                        return path.substring(lastDelimiter + 1);
1057
                else {
1058
                        // Remove the trailing delimiter and then recurse.
1059
                        String strippedTrail = path.substring(0, lastDelimiter);
1060
                        return getLastElement(strippedTrail);
1061
                }
1062
        }
1063

    
1064
        @Override
1065
        public void moveFileToTrash(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1066
                if (userId == null)
1067
                        throw new ObjectNotFoundException("No user specified");
1068
                if (fileId == null)
1069
                        throw new ObjectNotFoundException("No file specified");
1070

    
1071
                // Do the actual work.
1072
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1073
                Folder parent = file.getFolder();
1074
                if (parent == null)
1075
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1076
                User user = dao.getEntityById(User.class, userId);
1077
                if (!file.hasDeletePermission(user))
1078
                        throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1079

    
1080
                file.setDeleted(true);
1081
                dao.update(file);
1082
        }
1083

    
1084
        @Override
1085
        public void moveFileToPath(Long userId, Long ownerId, Long fileId, String dest) throws ObjectNotFoundException, InsufficientPermissionsException, QuotaExceededException {
1086
                if (userId == null)
1087
                        throw new ObjectNotFoundException("No user specified");
1088
                if (ownerId == null)
1089
                        throw new ObjectNotFoundException("No owner specified");
1090
                if (fileId == null)
1091
                        throw new ObjectNotFoundException("No file specified");
1092
                if (StringUtils.isEmpty(dest))
1093
                        throw new ObjectNotFoundException("No destination specified");
1094

    
1095
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1096
                if (!(destination instanceof FolderDTO))
1097
                        throw new ObjectNotFoundException("Destination parent folder not found");
1098
                FolderDTO parent = (FolderDTO) destination;
1099
                moveFile(userId, fileId, parent.getId(), getLastElement(dest));
1100
        }
1101

    
1102
        @Override
1103
        public void moveFile(Long userId, Long fileId, Long destId, String destName) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1104
                if (userId == null)
1105
                        throw new ObjectNotFoundException("No user specified");
1106
                if (fileId == null)
1107
                        throw new ObjectNotFoundException("No file specified");
1108
                if (destId == null)
1109
                        throw new ObjectNotFoundException("No destination specified");
1110
                if (StringUtils.isEmpty(destName))
1111
                        throw new ObjectNotFoundException("No destination file name specified");
1112

    
1113
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1114
                Folder destination = dao.getEntityById(Folder.class, destId);
1115

    
1116
                User owner = dao.getEntityById(User.class, userId);
1117
                if (!file.hasDeletePermission(owner) || !destination.hasWritePermission(owner))
1118
                        throw new InsufficientPermissionsException("User " + owner.getId() + " cannot move file " + file.getName() + "(" + file.getId() + ")");
1119

    
1120
                // if the destination folder belongs to another user:
1121
                if (!file.getOwner().equals(destination.getOwner())) {
1122
                        // (a) check if the destination quota allows the move
1123
                        if(getQuotaLeft(destination.getOwner().getId()) < file.getTotalSize())
1124
                                throw new QuotaExceededException("Not enough free space available");
1125
                        User newOwner = destination.getOwner();
1126
                        // (b) if quota OK, change the owner of the file
1127
                        file.setOwner(newOwner);
1128
                        // if the file has no permission for the new owner, add it
1129
                        Permission ownerPermission = null;
1130
                        for (final Permission p : file.getPermissions())
1131
                                if (p.getUser() != null)
1132
                                        if (p.getUser().equals(newOwner)) {
1133
                                                ownerPermission = p;
1134
                                                break;
1135
                                        }
1136
                        if (ownerPermission == null) {
1137
                                ownerPermission = new Permission();
1138
                                ownerPermission.setUser(newOwner);
1139
                                file.addPermission(ownerPermission);
1140
                        }
1141
                        ownerPermission.setRead(true);
1142
                        ownerPermission.setWrite(true);
1143
                        ownerPermission.setModifyACL(true);
1144
                }
1145
                // move the file to the destination folder
1146
                file.setFolder(destination);
1147
        }
1148

    
1149
        @Override
1150
        public void moveFolderToPath(Long userId, Long ownerId, Long folderId, String dest) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1151
                if (userId == null)
1152
                        throw new ObjectNotFoundException("No user specified");
1153
                if (ownerId == null)
1154
                        throw new ObjectNotFoundException("No owner specified");
1155
                if (folderId == null)
1156
                        throw new ObjectNotFoundException("No folder specified");
1157
                if (StringUtils.isEmpty(dest))
1158
                        throw new ObjectNotFoundException("No destination specified");
1159

    
1160
                Object destination = getResourceAtPath(ownerId, getParentPath(dest), true);
1161
                if (!(destination instanceof FolderDTO))
1162
                        throw new ObjectNotFoundException("Destination parent folder not found");
1163
                FolderDTO parent = (FolderDTO) destination;
1164
                moveFolder(userId, folderId, parent.getId(), getLastElement(dest));
1165
        }
1166

    
1167
        @Override
1168
        public void moveFolder(Long userId, Long folderId, Long destId, String destName) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException, GSSIOException, QuotaExceededException {
1169
                // TODO Simple Move and delete of original folder, in production
1170
                // scenario we must first check individual files and folders permissions
1171
                copyFolderStructure(userId, folderId, destId, destName);
1172
                deleteFolder(userId, folderId);
1173
        }
1174

    
1175
        /* (non-Javadoc)
1176
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getDeletedFiles(java.lang.Long)
1177
         */
1178
        public List<FileHeaderDTO> getDeletedFiles(Long userId) throws ObjectNotFoundException {
1179
                // Validate.
1180
                if (userId == null)
1181
                        throw new ObjectNotFoundException("No user specified");
1182

    
1183
                // Do the actual work.
1184
                final List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1185
                final List<FileHeader> files = dao.getDeletedFiles(userId);
1186
                for (final FileHeader f : files)
1187
                        result.add(f.getDTO());
1188
                return result;
1189
        }
1190

    
1191
        @Override
1192
        public void removeFileFromTrash(Long userId, Long fileId)
1193
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1194
                if (userId == null)
1195
                        throw new ObjectNotFoundException("No user specified");
1196
                if (fileId == null)
1197
                        throw new ObjectNotFoundException("No file specified");
1198

    
1199
                // Do the actual work.
1200
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1201
                Folder parent = file.getFolder();
1202
                if (parent == null)
1203
                        throw new ObjectNotFoundException("The specified file has no parent folder");
1204
                User user = dao.getEntityById(User.class, userId);
1205
                if (!file.hasDeletePermission(user))
1206
                        throw new InsufficientPermissionsException("User " + user.getUsername() +
1207
                                                " cannot restore file " + file.getName());
1208

    
1209
                file.setDeleted(false);
1210
                dao.update(file);
1211
        }
1212

    
1213
        @Override
1214
        public void moveFolderToTrash(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1215
                if (userId == null)
1216
                        throw new ObjectNotFoundException("No user specified");
1217
                if (folderId == null)
1218
                        throw new ObjectNotFoundException("No folder specified");
1219
                Folder folder = dao.getEntityById(Folder.class, folderId);
1220
                User user = dao.getEntityById(User.class, userId);
1221
                if (!folder.hasDeletePermission(user))
1222
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1223
                folder.setDeleted(true);
1224
                dao.update(folder);
1225
                for (FileHeader file : folder.getFiles())
1226
                        moveFileToTrash(userId, file.getId());
1227
                for (Folder subFolder : folder.getSubfolders())
1228
                        moveFolderToTrash(userId, subFolder.getId());
1229

    
1230
        }
1231

    
1232
        @Override
1233
        public void removeFolderFromTrash(Long userId, Long folderId)
1234
                        throws ObjectNotFoundException, InsufficientPermissionsException {
1235
                if (userId == null)
1236
                        throw new ObjectNotFoundException("No user specified");
1237
                if (folderId == null)
1238
                        throw new ObjectNotFoundException("No folder specified");
1239
                Folder folder = dao.getEntityById(Folder.class, folderId);
1240
                User user = dao.getEntityById(User.class, userId);
1241
                if (!folder.hasDeletePermission(user))
1242
                        throw new InsufficientPermissionsException("User " + user.getUsername() +
1243
                                                " cannot restore folder " + folder.getName());
1244
                folder.setDeleted(false);
1245
                for (FileHeader file : folder.getFiles())
1246
                        removeFileFromTrash(userId, file.getId());
1247
                for (Folder subFolder : folder.getSubfolders())
1248
                        removeFolderFromTrash(userId, subFolder.getId());
1249
                dao.update(folder);
1250
        }
1251

    
1252
        @Override
1253
        public List<FolderDTO> getDeletedRootFolders(Long userId) throws ObjectNotFoundException {
1254
                List<Folder> folders = dao.getDeletedRootFolders(userId);
1255
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1256
                for (Folder folder : folders)
1257
                        result.add(folder.getDTO());
1258
                return result;
1259
        }
1260

    
1261
        @Override
1262
        public void emptyTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1263
                List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1264
                for (FolderDTO fdto : deletedRootFolders)
1265
                        deleteFolder(userId, fdto.getId());
1266
                List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1267
                for (FileHeaderDTO filedto : deletedFiles)
1268
                        deleteFile(userId, filedto.getId());
1269
        }
1270

    
1271
        @Override
1272
        public void restoreTrash(Long userId) throws ObjectNotFoundException, InsufficientPermissionsException {
1273
                List<FolderDTO> deletedRootFolders = getDeletedRootFolders(userId);
1274
                for (FolderDTO fdto : deletedRootFolders)
1275
                        removeFolderFromTrash(userId, fdto.getId());
1276
                List<FileHeaderDTO> deletedFiles = getDeletedFiles(userId);
1277
                for (FileHeaderDTO filedto : deletedFiles)
1278
                        removeFileFromTrash(userId, filedto.getId());
1279
        }
1280

    
1281
        @Override
1282
        public User createUser(String username, String name, String mail) throws ObjectNotFoundException {
1283
                if (username == null)
1284
                        throw new ObjectNotFoundException("No username specified");
1285
                if (name == null)
1286
                        throw new ObjectNotFoundException("No name specified");
1287

    
1288
                User user = new User();
1289
                user.setUsername(username);
1290
                user.setName(name);
1291
                user.setEmail(mail);
1292
                Date now = new Date();
1293
                AuditInfo auditInfo = new AuditInfo();
1294
                auditInfo.setCreationDate(now);
1295
                auditInfo.setModificationDate(now);
1296
                user.setAuditInfo(auditInfo);
1297
                user.generateAuthToken();
1298
                user.generateWebDAVPassword();
1299
                dao.create(user);
1300
                // Make sure we get an ID in the user object.
1301
                dao.flush();
1302
                // Create the root folder for the user.
1303
                createFolder(user.getName(), null, user);
1304
                return user;
1305
        }
1306

    
1307
        @Override
1308
        public User findUserByEmail(String email) {
1309
                return dao.findUserByEmail(email);
1310
        }
1311

    
1312
        @Override
1313
        public void updateUser(User user) {
1314
                dao.update(user);
1315
        }
1316

    
1317
        @Override
1318
        public User updateUser(String username, String name, String mail) throws ObjectNotFoundException {
1319
                if (username == null)
1320
                        throw new ObjectNotFoundException("No username specified");
1321

    
1322
                User user = dao.getUser(username);
1323
                user.setName(name);
1324
                user.setEmail(mail);
1325
                return user;
1326
        }
1327

    
1328
        @Override
1329
        public User findUser(String username) {
1330
                if (username == null)
1331
                        return null;
1332
                return dao.findUser(username);
1333
        }
1334

    
1335
        @Override
1336
        public User updateUserToken(Long userId) throws ObjectNotFoundException {
1337
                if (userId == null)
1338
                        throw new ObjectNotFoundException("No user specified");
1339
                User user = dao.getEntityById(User.class, userId);
1340
                user.generateAuthToken();
1341
                return user;
1342
        }
1343

    
1344
        /* (non-Javadoc)
1345
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFolderPermissions(java.lang.Long, java.lang.Long)
1346
         */
1347
        @Override
1348
        public Set<PermissionDTO> getFolderPermissions(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
1349
                if (userId == null)
1350
                        throw new ObjectNotFoundException("No user specified");
1351
                if (folderId == null)
1352
                        throw new ObjectNotFoundException("No folder specified");
1353
                User user = dao.getEntityById(User.class, userId);
1354
                Folder folder = dao.getEntityById(Folder.class, folderId);
1355
                if(!folder.hasReadPermission(user))
1356
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1357
                Set<Permission> perms = folder.getPermissions();
1358
                Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1359
                for (Permission perm : perms)
1360
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1361
                                result.add(perm.getDTO());
1362
                for (Permission perm : perms)
1363
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1364
                        } else
1365
                                result.add(perm.getDTO());
1366
                return result;
1367

    
1368
        }
1369

    
1370
        /* (non-Javadoc)
1371
         * @see gr.ebs.gss.server.ejb.ExternalAPI#setFolderPermissions(java.lang.Long, java.lang.Long, java.util.Set)
1372
         */
1373
        @Override
1374
        public void setFolderPermissions(Long userId, Long folderId, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1375
                if (userId == null)
1376
                        throw new ObjectNotFoundException("No user specified");
1377
                if (folderId == null)
1378
                        throw new ObjectNotFoundException("No folder specified");
1379
                User user = dao.getEntityById(User.class, userId);
1380
                Folder folder = dao.getEntityById(Folder.class, folderId);
1381
                if(!folder.hasModifyACLPermission(user))
1382
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1383
                // Delete previous entries
1384
                for (Permission perm: folder.getPermissions())
1385
                        dao.delete(perm);
1386
                folder.getPermissions().clear();
1387
                for (PermissionDTO dto : permissions) {
1388
                        if (dto.getUser()!=null && dto.getUser().getId().equals(folder.getOwner().getId()) && (!dto.hasRead() || !dto.hasWrite() || !dto.hasModifyACL()))
1389
                                        throw new InsufficientPermissionsException("Can't remove permissions from owner");
1390
                        // Don't include 'empty' permission
1391
                        if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1392
                        folder.addPermission(getPermission(dto));
1393
                }
1394
                dao.update(folder);
1395
                for (FileHeader fh : folder.getFiles())
1396
                        setFilePermissions(userId, fh.getId(), fh.isReadForAll(), permissions);
1397
                for (Folder sub : folder.getSubfolders())
1398
                        setFolderPermissions(userId, sub.getId(), permissions);
1399
        }
1400

    
1401
        private Permission getPermission(PermissionDTO dto) throws ObjectNotFoundException {
1402
                Permission res = new Permission();
1403
                if (dto.getGroup() != null)
1404
                        res.setGroup(dao.getEntityById(Group.class, dto.getGroup().getId()));
1405
                else if (dto.getUser() != null)
1406
                        if (dto.getUser().getId() == null)
1407
                                res.setUser(dao.getUser(dto.getUser().getUsername()));
1408
                        else
1409
                                res.setUser(dao.getEntityById(User.class, dto.getUser().getId()));
1410
                res.setRead(dto.hasRead());
1411
                res.setWrite(dto.hasWrite());
1412
                res.setModifyACL(dto.hasModifyACL());
1413
                return res;
1414
        }
1415

    
1416
        /* (non-Javadoc)
1417
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersByUserNameLike(java.lang.String)
1418
         */
1419
        @Override
1420
        public List<UserDTO> getUsersByUserNameLike(String username) {
1421
                List<User> users = dao.getUsersByUserNameLike(username);
1422
                List<UserDTO> result = new ArrayList<UserDTO>();
1423
                for (User u : users)
1424
                        result.add(u.getDTO());
1425
                return result;
1426

    
1427
        }
1428

    
1429
        /* (non-Javadoc)
1430
         * @see gr.ebs.gss.server.ejb.ExternalAPI#addUserToGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1431
         */
1432
        @Override
1433
        public void addUserToGroup(Long userId, Long groupId, Long userToAddId) throws ObjectNotFoundException, DuplicateNameException, InsufficientPermissionsException {
1434
                if (userId == null)
1435
                        throw new ObjectNotFoundException("No user specified");
1436
                if (groupId == null)
1437
                        throw new ObjectNotFoundException("No group specified");
1438
                if (userToAddId == null)
1439
                        throw new ObjectNotFoundException("No user to add specified");
1440
                User user = dao.getEntityById(User.class, userId);
1441
                Group group = dao.getEntityById(Group.class, groupId);
1442
                if (!group.getOwner().equals(user))
1443
                        throw new InsufficientPermissionsException();
1444
                User userToAdd = dao.getEntityById(User.class, userToAddId);
1445
                if (group.contains(userToAdd))
1446
                        throw new DuplicateNameException("User already exists in group");
1447
                group.getMembers().add(userToAdd);
1448
                dao.update(group);
1449

    
1450
        }
1451

    
1452
        @Override
1453
        public void invalidateUserToken(Long userId) throws ObjectNotFoundException {
1454
                if (userId == null)
1455
                        throw new ObjectNotFoundException("No user specified");
1456
                User user = dao.getEntityById(User.class, userId);
1457
                user.invalidateAuthToken();
1458
                return;
1459
        }
1460

    
1461
        @Override
1462
        public List<FolderDTO> getSharedRootFolders(Long userId) throws ObjectNotFoundException {
1463
                if (userId == null)
1464
                        throw new ObjectNotFoundException("No user specified");
1465
                List<Folder> folders = dao.getSharedRootFolders(userId);
1466
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1467
                for (Folder f : folders) {
1468
                        FolderDTO dto = f.getDTO();
1469
                        dto.setSubfolders(getSharedSubfolders(userId, f.getId()));
1470
                        result.add(dto);
1471
                }
1472
                return result;
1473
        }
1474

    
1475
        /* (non-Javadoc)
1476
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeMemberFromGroup(java.lang.Long, java.lang.Long, java.lang.Long)
1477
         */
1478
        @Override
1479
        public void removeMemberFromGroup(Long userId, Long groupId, Long memberId) throws ObjectNotFoundException, InsufficientPermissionsException {
1480
                if (userId == null)
1481
                        throw new ObjectNotFoundException("No user specified");
1482
                if (groupId == null)
1483
                        throw new ObjectNotFoundException("No group specified");
1484
                if (memberId == null)
1485
                        throw new ObjectNotFoundException("No member specified");
1486
                User owner = dao.getEntityById(User.class, userId);
1487
                Group group = dao.getEntityById(Group.class, groupId);
1488
                User member = dao.getEntityById(User.class, memberId);
1489
                if (!group.getOwner().equals(owner))
1490
                        throw new InsufficientPermissionsException("User is not the owner of the group");
1491
                group.removeMemberFromGroup(member);
1492
                dao.update(group);
1493

    
1494
        }
1495

    
1496
        /* (non-Javadoc)
1497
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUsersSharingFoldersForUser(java.lang.Long)
1498
         */
1499
        @Override
1500
        public List<UserDTO> getUsersSharingFoldersForUser(Long userId) throws ObjectNotFoundException {
1501
                List<User> users = dao.getUsersSharingFoldersForUser(userId);
1502
                List<User> usersFiles = dao.getUsersSharingFilesForUser(userId);
1503
                List<UserDTO> res = new ArrayList<UserDTO>();
1504
                for (User u : users)
1505
                        res.add(u.getDTO());
1506
                for(User fu : usersFiles)
1507
                        if(!users.contains(fu))
1508
                                res.add(fu.getDTO());
1509
                return res;
1510
        }
1511

    
1512
        /* (non-Javadoc)
1513
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getFilePermissions(java.lang.Long, java.lang.Long)
1514
         */
1515
        @Override
1516
        public Set<PermissionDTO> getFilePermissions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1517
                if (userId == null)
1518
                        throw new ObjectNotFoundException("No user specified");
1519
                if (fileId == null)
1520
                        throw new ObjectNotFoundException("No folder specified");
1521
                User user = dao.getEntityById(User.class, userId);
1522
                FileHeader folder = dao.getEntityById(FileHeader.class, fileId);
1523
                if(!folder.hasReadPermission(user))
1524
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1525
                Set<Permission> perms = folder.getPermissions();
1526
                Set<PermissionDTO> result = new LinkedHashSet<PermissionDTO>();
1527
                for (Permission perm : perms)
1528
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId()))
1529
                                result.add(perm.getDTO());
1530
                for (Permission perm : perms)
1531
                        if (perm.getUser() != null && perm.getUser().getId().equals(folder.getOwner().getId())) {
1532
                        } else
1533
                                result.add(perm.getDTO());
1534
                return result;
1535
        }
1536

    
1537
        @Override
1538
        public void setFilePermissions(Long userId, Long fileId, Boolean readForAll, Set<PermissionDTO> permissions) throws ObjectNotFoundException, InsufficientPermissionsException {
1539
                if (userId == null)
1540
                        throw new ObjectNotFoundException("No user specified");
1541
                if (fileId == null)
1542
                        throw new ObjectNotFoundException("No folder specified");
1543

    
1544
                User user = dao.getEntityById(User.class, userId);
1545
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1546
                if(!file.hasModifyACLPermission(user))
1547
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1548

    
1549
                if (readForAll != null)
1550
                        if (user.equals(file.getOwner()))
1551
                                file.setReadForAll(readForAll);
1552
                        else
1553
                                throw new InsufficientPermissionsException("Only the owner can change the read-for-all flag");
1554

    
1555
                // Update the file if there was a change.
1556
                if (readForAll != null || permissions != null && !permissions.isEmpty()) {
1557
                        if (permissions != null && !permissions.isEmpty()) {
1558
                                // Delete previous entries
1559
                                for (Permission perm: file.getPermissions())
1560
                                        dao.delete(perm);
1561
                                file.getPermissions().clear();
1562
                                for (PermissionDTO dto : permissions) {
1563
                                        if (dto.getUser()!=null && dto.getUser().getId().equals(file.getOwner().getId()) && (!dto.hasRead() || !dto.hasWrite() || !dto.hasModifyACL()))
1564
                                                throw new InsufficientPermissionsException("Can't remove permissions from owner");
1565
                                        // Don't include 'empty' permission
1566
                                        if (!dto.getRead() && !dto.getWrite() && !dto.getModifyACL()) continue;
1567
                                        file.addPermission(getPermission(dto));
1568
                                }
1569
                        }
1570

    
1571
                        dao.update(file);
1572
                }
1573
        }
1574

    
1575
        @Override
1576
        public List<FileHeaderDTO> getSharedFilesNotInSharedFolders(Long userId) throws ObjectNotFoundException {
1577
                if (userId == null)
1578
                        throw new ObjectNotFoundException("No user specified");
1579
                List<FileHeader> files = dao.getSharedFilesNotInSharedFolders(userId);
1580
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1581
                for (FileHeader f : files)
1582
                        result.add(f.getDTO());
1583
                return result;
1584
        }
1585

    
1586
        @Override
1587
        public List<FileHeaderDTO> getSharedFiles(Long userId) throws ObjectNotFoundException {
1588
                if (userId == null)
1589
                        throw new ObjectNotFoundException("No user specified");
1590
                List<FileHeader> files = dao.getSharedFiles(userId);
1591
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1592
                for (FileHeader f : files)
1593
                        result.add(f.getDTO());
1594
                return result;
1595
        }
1596

    
1597
        @Override
1598
        public List<FolderDTO> getSharedFolders(Long userId) throws ObjectNotFoundException {
1599
                if (userId == null)
1600
                        throw new ObjectNotFoundException("No user specified");
1601
                List<Folder> folders = dao.getSharedFolders(userId);
1602
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1603
                for (Folder f : folders)
1604
                        result.add(f.getDTO());
1605
                return result;
1606
        }
1607

    
1608
        /* (non-Javadoc)
1609
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getSharedFiles(java.lang.Long, java.lang.Long)
1610
         */
1611
        @Override
1612
        public List<FileHeaderDTO> getSharedFiles(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1613
                if (ownerId == null)
1614
                        throw new ObjectNotFoundException("No owner specified");
1615
                if (callingUserId == null)
1616
                        throw new ObjectNotFoundException("No calling user specified");
1617
                List<FileHeader> folders = dao.getSharedFiles(ownerId, callingUserId);
1618
                List<FileHeaderDTO> result = new ArrayList<FileHeaderDTO>();
1619
                for (FileHeader f : folders)
1620
                        result.add(f.getDTO());
1621
                return result;
1622
        }
1623

    
1624
        @Override
1625
        public List<FolderDTO> getSharedRootFolders(Long ownerId, Long callingUserId) throws ObjectNotFoundException {
1626
                if (ownerId == null)
1627
                        throw new ObjectNotFoundException("No owner specified");
1628
                if (callingUserId == null)
1629
                        throw new ObjectNotFoundException("No calling user specified");
1630
                List<Folder> folders = dao.getSharedRootFolders(ownerId, callingUserId);
1631
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1632
                for (Folder f : folders) {
1633
                        FolderDTO dto = f.getDTO();
1634
                        dto.setSubfolders(getSharedSubfolders(ownerId, callingUserId, f.getId()));
1635
                        result.add(dto);
1636
                }
1637
                return result;
1638

    
1639
        }
1640

    
1641
        @Override
1642
        public List<FolderDTO> getSharedSubfolders(Long userId, Long folderId) throws ObjectNotFoundException {
1643
                if (userId == null)
1644
                        throw new ObjectNotFoundException("No user specified");
1645
                if (folderId == null)
1646
                        throw new ObjectNotFoundException("No folder specified");
1647
                User user = dao.getEntityById(User.class, userId);
1648
                Folder folder = dao.getEntityById(Folder.class, folderId);
1649
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1650
                if (folder.isShared(user))
1651
                        for (Folder f : folder.getSubfolders())
1652
                                if (f.isShared(user) && !f.isDeleted())
1653
                                        result.add(f.getDTO());
1654
                return result;
1655
        }
1656

    
1657
        @Override
1658
        public List<FolderDTO> getSharedSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException {
1659
                if (userId == null)
1660
                        throw new ObjectNotFoundException("No user specified");
1661
                if (callingUserId == null)
1662
                        throw new ObjectNotFoundException("No user specified");
1663
                if (folderId == null)
1664
                        throw new ObjectNotFoundException("No folder specified");
1665
                User user = dao.getEntityById(User.class, callingUserId);
1666
                Folder folder = dao.getEntityById(Folder.class, folderId);
1667
                List<FolderDTO> result = new ArrayList<FolderDTO>();
1668
                if (folder.isSharedForOtherUser(user))
1669
                        for (Folder f : folder.getSubfolders())
1670
                                if (f.isSharedForOtherUser(user) && !f.isDeleted()){
1671
                                        FolderDTO dto = f.getDTO();
1672
                                        dto.setSubfolders(getSharedSubfolders(userId, callingUserId, dto.getId()));
1673
                                        result.add(dto);
1674
                                }
1675
                return result;
1676

    
1677
        }
1678

    
1679
        /* (non-Javadoc)
1680
         * @see gr.ebs.gss.server.ejb.ExternalAPI#searchFiles(java.lang.Long, java.lang.String)
1681
         */
1682
        @Override
1683
        public List<FileHeaderDTO> searchFiles(Long userId, String query) throws ObjectNotFoundException {
1684
                if (userId == null)
1685
                        throw new ObjectNotFoundException("No user specified");
1686
                User user = getUser(userId);
1687
                if (query == null)
1688
                        throw new ObjectNotFoundException("No query specified");
1689
                List<FileHeader> files = search(user.getId(), query);
1690
                List<FileHeaderDTO> res = new ArrayList<FileHeaderDTO>();
1691
                for(FileHeader f : files)
1692
                        res.add(f.getDTO());
1693
                return res;
1694
        }
1695

    
1696
        /**
1697
         * Performs the actuals search on the solr server and returns the results
1698
         *
1699
         * We have to use the dismax query type (instead of the
1700
         * standard) because it allows for search time field boosting. This is because we can't use indexing
1701
         * time field boosting due to the patched rich indexing API that does not allow it
1702
         *
1703
         * @param userId
1704
         * @param query
1705
         * @return a List of FileHeader objects
1706
         */
1707
        private List<FileHeader> search(Long userId, String query) {
1708
                try {
1709
                        HttpClient httpClient = new HttpClient();
1710

    
1711
                        GetMethod method = new GetMethod(getConfiguration().getString("solrSelectUrl"));
1712
                        NameValuePair[] params = {new NameValuePair("qt", "dismax"),
1713
                                                                                new NameValuePair("q", query),
1714
                                                                                new NameValuePair("sort", "score desc"),
1715
                                                                                new NameValuePair("indent", "on")};
1716
                        method.setQueryString(params);
1717
                        int retryCount = 0;
1718
                        int statusCode = 0;
1719
                        String response = null;
1720
                        do {
1721
                                statusCode = httpClient.executeMethod(method);
1722
                                logger.debug("HTTP status: " + statusCode);
1723
                                response = method.getResponseBodyAsString();
1724
                                logger.debug(response);
1725
                                retryCount++;
1726
                                if (statusCode != 200 && retryCount < 3)
1727
                                        try {
1728
                                                Thread.sleep(3000); //Give Solr a little time to be available
1729
                                        } catch (InterruptedException e) {
1730
                                        }
1731
                        } while (statusCode != 200 && retryCount < 3);
1732
                        if (statusCode != 200)
1733
                                throw new EJBException("Search query return error:\n" + response);
1734

    
1735
                        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1736
                        DocumentBuilder db = dbf.newDocumentBuilder();
1737
                        Document doc = db.parse(method.getResponseBodyAsStream());
1738
                        method.releaseConnection();
1739

    
1740
                        Node root = doc.getElementsByTagName("response").item(0);
1741
                        Node lst = root.getFirstChild().getNextSibling();
1742
                        Node status = lst.getFirstChild().getNextSibling();
1743
                        if (status.getAttributes().getNamedItem("name").getNodeValue().equals("status") &&
1744
                                status.getTextContent().equals("0")) {
1745
                                List<FileHeader> fileResult = new ArrayList<FileHeader>();
1746
                                Node result = lst.getNextSibling().getNextSibling();
1747
                                NodeList docs = result.getChildNodes();
1748
                                User user = getUser(userId);
1749
                                for (int i=1; i<docs.getLength(); i=i+2) {
1750
                                        Node d = docs.item(i);
1751
                                        NodeList docData = d.getChildNodes();
1752
                                        for (int j=1; j<docData.getLength(); j=j+2) {
1753
                                                Node dd = docData.item(j);
1754
                                                if (dd.getAttributes().item(0).getNodeName().equals("name") &&
1755
                                                        dd.getAttributes().item(0).getNodeValue().equals("id")) {
1756
                                                        Long fileId = Long.valueOf(dd.getTextContent());
1757
                                                        try {
1758
                                                                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1759
                                                                if (file.hasReadPermission(user)) {
1760
                                                                        fileResult.add(file);
1761
                                                                        logger.debug("File added " + fileId);
1762
                                                                }
1763
                                                        } catch (ObjectNotFoundException e) {
1764
                                                                logger.warn("Search result not found", e);
1765
                                                        }
1766
                                                }
1767
                                        }
1768
                                }
1769
                                return fileResult;
1770
                        }
1771
                        throw new EJBException();
1772
                } catch (HttpException e) {
1773
                        throw new EJBException(e);
1774
                } catch (IOException e) {
1775
                        throw new EJBException(e);
1776
                } catch (SAXException e) {
1777
                        throw new EJBException(e);
1778
                } catch (ParserConfigurationException e) {
1779
                        throw new EJBException(e);
1780
                } catch (ObjectNotFoundException e) {
1781
                        throw new EJBException(e);
1782
                }
1783
        }
1784

    
1785
        /* (non-Javadoc)
1786
         * @see gr.ebs.gss.server.ejb.ExternalAPI#copyFiles(java.lang.Long, java.util.List, java.lang.Long)
1787
         */
1788
        @Override
1789
        public void copyFiles(Long userId, List<Long> fileIds, Long destId) throws ObjectNotFoundException, DuplicateNameException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
1790
                for(Long l : fileIds){
1791
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1792
                        copyFile(userId, l, destId, file.getName());
1793
                }
1794

    
1795

    
1796
        }
1797

    
1798
        /* (non-Javadoc)
1799
         * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFiles(java.lang.Long, java.util.List, java.lang.Long)
1800
         */
1801
        @Override
1802
        public void moveFiles(Long userId, List<Long> fileIds, Long destId) throws InsufficientPermissionsException, ObjectNotFoundException, QuotaExceededException {
1803
                for(Long l : fileIds){
1804
                        FileHeader file = dao.getEntityById(FileHeader.class, l);
1805
                        moveFile(userId, l, destId, file.getName());
1806
                }
1807

    
1808
        }
1809

    
1810
        /* (non-Javadoc)
1811
         * @see gr.ebs.gss.server.ejb.ExternalAPI#deleteFiles(java.lang.Long, java.util.List)
1812
         */
1813
        @Override
1814
        public void deleteFiles(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1815
                if (userId == null)
1816
                        throw new ObjectNotFoundException("No user specified");
1817
                final User user = dao.getEntityById(User.class, userId);
1818
                List<String> filesToRemove = new ArrayList<String>();
1819
                //first delete database objects
1820
                for(Long fileId : fileIds){
1821
                        if (fileId == null)
1822
                                throw new ObjectNotFoundException("No file specified");
1823
                        final FileHeader file = dao.getEntityById(FileHeader.class, fileId);
1824
                        final Folder parent = file.getFolder();
1825
                        if (parent == null)
1826
                                throw new ObjectNotFoundException("The specified file has no parent folder");
1827
                        if (!file.hasDeletePermission(user))
1828
                                throw new InsufficientPermissionsException("User " + user.getId() + " cannot delete file " + file.getName() + "(" + file.getId() + ")");
1829

    
1830
                        parent.removeFile(file);
1831
                        for (final FileBody body : file.getBodies())
1832
                                filesToRemove.add(body.getStoredFilePath());
1833
                        dao.delete(file);
1834
                }
1835
                //then remove physical files if everything is ok
1836
                for(String physicalFileName : filesToRemove)
1837
                        deleteActualFile(physicalFileName);
1838
                //then unindex deleted files
1839
                for(Long fileId : fileIds)
1840
                        indexFile(fileId, true);
1841

    
1842
        }
1843

    
1844
        /* (non-Javadoc)
1845
         * @see gr.ebs.gss.server.ejb.ExternalAPI#moveFilesToTrash(java.lang.Long, java.util.List)
1846
         */
1847
        @Override
1848
        public void moveFilesToTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1849
                for(Long l : fileIds)
1850
                        moveFileToTrash(userId, l);
1851

    
1852
        }
1853

    
1854
        @Override
1855
        public void removeFilesFromTrash(Long userId, List<Long> fileIds) throws ObjectNotFoundException, InsufficientPermissionsException {
1856
                for(Long l : fileIds)
1857
                        removeFileFromTrash(userId, l);
1858

    
1859
        }
1860

    
1861
        @Override
1862
        public Nonce createNonce(Long userId) throws ObjectNotFoundException {
1863
                if (userId == null)
1864
                        throw new ObjectNotFoundException("No user specified");
1865
                User user = dao.getEntityById(User.class, userId);
1866
                Nonce nonce = Nonce.createNonce(user.getId());
1867
                dao.create(nonce);
1868
                return nonce;
1869
        }
1870

    
1871
        @Override
1872
        public Nonce getNonce(String nonce, Long userId) throws ObjectNotFoundException {
1873
                if (userId == null)
1874
                        throw new ObjectNotFoundException("No user specified");
1875
                if (nonce == null)
1876
                        throw new ObjectNotFoundException("No nonce specified");
1877
                return dao.getNonce(nonce, userId);
1878
        }
1879

    
1880
        @Override
1881
        public void removeNonce(Long id) throws ObjectNotFoundException {
1882
                if (id == null)
1883
                        throw new ObjectNotFoundException("No nonce specified");
1884
                Nonce nonce = dao.getEntityById(Nonce.class, id);
1885
                dao.delete(nonce);
1886
        }
1887

    
1888
        @Override
1889
        public void activateUserNonce(Long userId, String nonce, Date nonceExpiryDate) throws ObjectNotFoundException {
1890
                if (userId == null)
1891
                        throw new ObjectNotFoundException("No user specified");
1892
                User user = dao.getEntityById(User.class, userId);
1893
                user.setNonce(nonce);
1894
                user.setNonceExpiryDate(nonceExpiryDate);
1895
        }
1896

    
1897
        /* (non-Javadoc)
1898
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getUserStatistics(java.lang.Long)
1899
         */
1900
        @Override
1901
        public StatsDTO getUserStatistics(Long userId) throws ObjectNotFoundException {
1902
                if (userId == null)
1903
                        throw new ObjectNotFoundException("No user specified");
1904
                StatsDTO stats = new StatsDTO();
1905
                stats.setFileCount(dao.getFileCount(userId));
1906
                Long fileSize = dao.getFileSize(userId);
1907
                stats.setFileSize(fileSize);
1908
                Long quota = getQuota(userId);
1909
                Long quotaLeft = quota - fileSize;
1910
                stats.setQuotaLeftSize(quotaLeft);
1911
                return stats;
1912
        }
1913

    
1914
        /* (non-Javadoc)
1915
         * @see gr.ebs.gss.server.ejb.ExternalAPI#getVersions(java.lang.Long, java.lang.Long)
1916
         */
1917
        @Override
1918
        public List<FileBodyDTO> getVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1919
                if (userId == null)
1920
                        throw new ObjectNotFoundException("No user specified");
1921
                if (fileId == null)
1922
                        throw new ObjectNotFoundException("No file specified");
1923
                User user = dao.getEntityById(User.class, userId);
1924
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1925
                if(!header.hasReadPermission(user))
1926
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1927
                List<FileBodyDTO> result = new LinkedList<FileBodyDTO>();
1928
                for(int i = header.getBodies().size()-1 ; i>=0; i--)
1929
                        result.add(header.getBodies().get(i).getDTO());
1930
                return result;
1931
        }
1932

    
1933
        /* (non-Javadoc)
1934
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeVersion(java.lang.Long, java.lang.Long, java.lang.Long)
1935
         */
1936
        @Override
1937
        public void removeVersion(Long userId, Long fileId, Long bodyId) throws ObjectNotFoundException, InsufficientPermissionsException {
1938
                if (userId == null)
1939
                        throw new ObjectNotFoundException("No user specified");
1940
                if (fileId == null)
1941
                        throw new ObjectNotFoundException("No file specified");
1942
                if (bodyId == null)
1943
                        throw new ObjectNotFoundException("No body specified");
1944
                User user = dao.getEntityById(User.class, userId);
1945
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1946
                if(!header.hasWritePermission(user))
1947
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1948
                FileBody body = dao.getEntityById(FileBody.class, bodyId);
1949
                if(body.equals(header.getCurrentBody())){
1950

    
1951
                        if(header.getBodies().size() == 1)
1952
                                throw new InsufficientPermissionsException("You cant delete this version, Delete file instead!");
1953
                        for(FileBody b : header.getBodies())
1954
                                if(b.getVersion() == body.getVersion()-1)
1955
                                        header.setCurrentBody(b);
1956
                }
1957
                deleteActualFile(body.getStoredFilePath());
1958
                header.getBodies().remove(body);
1959

    
1960

    
1961
        }
1962

    
1963
        @Override
1964
        public void restoreVersion(Long userId, Long fileId, int version) throws ObjectNotFoundException, InsufficientPermissionsException,  GSSIOException, QuotaExceededException {
1965
                if (userId == null)
1966
                        throw new ObjectNotFoundException("No user specified");
1967
                if (fileId == null)
1968
                        throw new ObjectNotFoundException("No file specified");
1969
                User user = dao.getEntityById(User.class, userId);
1970
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1971
                if(!header.hasWritePermission(user))
1972
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1973
                FileBody body = dao.getFileVersion(fileId, version);
1974
                final File fileContents = new File(body.getStoredFilePath());
1975

    
1976
                try {
1977
                        updateFileContents(userId, fileId, body.getMimeType(), new FileInputStream(fileContents) );
1978
                } catch (FileNotFoundException e) {
1979
                        throw new GSSIOException(e);
1980
                }
1981

    
1982
        }
1983

    
1984
        /* (non-Javadoc)
1985
         * @see gr.ebs.gss.server.ejb.ExternalAPI#removeOldVersions(java.lang.Long, java.lang.Long)
1986
         */
1987
        @Override
1988
        public void removeOldVersions(Long userId, Long fileId) throws ObjectNotFoundException, InsufficientPermissionsException {
1989
                if (userId == null)
1990
                        throw new ObjectNotFoundException("No user specified");
1991
                if (fileId == null)
1992
                        throw new ObjectNotFoundException("No file specified");
1993
                User user = dao.getEntityById(User.class, userId);
1994
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
1995
                if(!header.hasWritePermission(user))
1996
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
1997
                Iterator<FileBody> it = header.getBodies().iterator();
1998
                while(it.hasNext()){
1999
                        FileBody body = it.next();
2000
                        if(!body.equals(header.getCurrentBody())){
2001
                                deleteActualFile(body.getStoredFilePath());
2002
                                it.remove();
2003
                                dao.delete(body);
2004
                        }
2005
                }
2006
                header.getCurrentBody().setVersion(1);
2007

    
2008
        }
2009

    
2010
        /* (non-Javadoc)
2011
         * @see gr.ebs.gss.server.ejb.ExternalAPI#toggleFileVersioning(java.lang.Long, java.lang.Long, boolean)
2012
         */
2013
        @Override
2014
        public void toggleFileVersioning(Long userId, Long fileId, boolean versioned) throws ObjectNotFoundException, InsufficientPermissionsException {
2015
                if (userId == null)
2016
                        throw new ObjectNotFoundException("No user specified");
2017
                if (fileId == null)
2018
                        throw new ObjectNotFoundException("No file specified");
2019
                User user = dao.getEntityById(User.class, userId);
2020
                FileHeader header = dao.getEntityById(FileHeader.class, fileId);
2021
                if(!header.hasWritePermission(user))
2022
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2023
                if(!header.isVersioned() == versioned){
2024
                        if(header.isVersioned())
2025
                                removeOldVersions(userId, fileId);
2026
                        header.setVersioned(versioned);
2027

    
2028
                }
2029
        }
2030

    
2031
        /**
2032
         * Gets the quota left for specified userId
2033
         * @param userId
2034
         * @return
2035
         */
2036
        private Long getQuotaLeft(Long userId){
2037
                Long fileSize = dao.getFileSize(userId);
2038
                Long quota = getQuota(userId);
2039
                return quota - fileSize;
2040
        }
2041

    
2042
        /**
2043
         * Gets the quota for specified userId
2044
         * @param userId
2045
         * @return
2046
         */
2047
        private Long getQuota(@SuppressWarnings("unused") Long userId){
2048
                Long quota = getConfiguration().getLong("quota", new Long(52428800L));
2049
                return quota;
2050
        }
2051

    
2052
        public void rebuildSolrIndex() {
2053
                MessageProducer sender = null;
2054
                Session session = null;
2055
                Connection qConn = null;
2056
                try {
2057
                        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
2058
                        DocumentBuilder db = dbf.newDocumentBuilder();
2059
                        Document doc = db.newDocument();
2060
                        Node root = doc.createElement("delete");
2061
                        doc.appendChild(root);
2062
                        Node queryNode = doc.createElement("query");
2063
                        root.appendChild(queryNode);
2064
                        queryNode.appendChild(doc.createTextNode("*:*"));
2065

    
2066
                        TransformerFactory fact = TransformerFactory.newInstance();
2067
                        Transformer trans = fact.newTransformer();
2068
                        trans.setOutputProperty(OutputKeys.INDENT, "yes");
2069
                        StringWriter sw = new StringWriter();
2070
                        StreamResult sr = new StreamResult(sw);
2071
                        DOMSource source = new DOMSource(doc);
2072
                        trans.transform(source, sr);
2073
                        logger.debug(sw.toString());
2074

    
2075
                        HttpClient httpClient = new HttpClient();
2076
                        PostMethod method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2077
                        method.setRequestEntity(new StringRequestEntity(sw.toString()));
2078
                        int retryCount = 0;
2079
                        int statusCode = 0;
2080
                        String response = null;
2081
                        do {
2082
                                statusCode = httpClient.executeMethod(method);
2083
                                logger.debug("HTTP status: " + statusCode);
2084
                                response = method.getResponseBodyAsString();
2085
                                logger.debug(response);
2086
                                retryCount++;
2087
                                if (statusCode != 200 && retryCount < 3)
2088
                                        try {
2089
                                                Thread.sleep(10000); //Give Solr a little time to be available
2090
                                        } catch (InterruptedException e) {
2091
                                        }
2092
                        } while (statusCode != 200 && retryCount < 3);
2093
                        method.releaseConnection();
2094
                        if (statusCode != 200)
2095
                                throw new EJBException("Cannot clear Solr index. Solr response is:\n" + response);
2096
                        List<Long> fileIds = dao.getAllFileIds();
2097

    
2098
                        Context jndiCtx = new InitialContext();
2099
                        ConnectionFactory factory = (QueueConnectionFactory) jndiCtx.lookup("java:/JmsXA");
2100
                        Queue queue = (Queue) jndiCtx.lookup("queue/gss-indexingQueue");
2101
                        qConn = factory.createConnection();
2102
                        session = qConn.createSession(false, Session.AUTO_ACKNOWLEDGE);
2103
                        sender = session.createProducer(queue);
2104

    
2105
                        for (Long id : fileIds) {
2106
                                MapMessage map = session.createMapMessage();
2107
                                map.setObject("id", id);
2108
                                map.setBoolean("delete", false);
2109
                                sender.send(map);
2110
                        }
2111
                        sendOptimize(httpClient, 0);
2112
                } catch (DOMException e) {
2113
                        throw new EJBException(e);
2114
                } catch (TransformerConfigurationException e) {
2115
                        throw new EJBException(e);
2116
                } catch (IllegalArgumentException e) {
2117
                        throw new EJBException(e);
2118
                } catch (HttpException e) {
2119
                        throw new EJBException(e);
2120
                } catch (UnsupportedEncodingException e) {
2121
                        throw new EJBException(e);
2122
                } catch (ParserConfigurationException e) {
2123
                        throw new EJBException(e);
2124
                } catch (TransformerException e) {
2125
                        throw new EJBException(e);
2126
                } catch (IOException e) {
2127
                        throw new EJBException(e);
2128
                } catch (NamingException e) {
2129
                        throw new EJBException(e);
2130
                } catch (JMSException e) {
2131
                        throw new EJBException(e);
2132
                }
2133
                finally {
2134
                        try {
2135
                                if (sender != null)
2136
                                        sender.close();
2137
                                if (session != null)
2138
                                        session.close();
2139
                                if (qConn != null)
2140
                                        qConn.close();
2141
                        }
2142
                        catch (JMSException e) {
2143
                                logger.warn(e);
2144
                        }
2145
                }
2146
        }
2147

    
2148
        /**
2149
         * Sends a optimize message to the solr server
2150
         *
2151
         * @param httpClient
2152
         * @param retryCount If the commit fails, it is retried three times. This parameter is passed in the recursive
2153
         *                                         calls to stop the recursion
2154
         * @throws UnsupportedEncodingException
2155
         * @throws IOException
2156
         * @throws HttpException
2157
         */
2158
        private void sendOptimize(HttpClient httpClient, int retryCount) throws UnsupportedEncodingException, IOException, HttpException {
2159
                PostMethod method = null;
2160
                try {
2161
                        logger.debug("Optimize retry: " + retryCount);
2162
                        method = new PostMethod(getConfiguration().getString("solrUpdateUrl"));
2163
                        method.setRequestEntity(new StringRequestEntity("<optimize/>", "text/xml", "iso8859-1"));
2164
                        int statusCode = httpClient.executeMethod(method);
2165
                        logger.debug("HTTP status: " + statusCode);
2166
                        String response = method.getResponseBodyAsString();
2167
                        logger.debug(response);
2168
                        if (statusCode != 200 && retryCount < 2) {
2169
                                try {
2170
                                        Thread.sleep(10000); //Give Solr a little time to be available
2171
                                } catch (InterruptedException e) {
2172
                                }
2173
                                sendOptimize(httpClient, retryCount + 1);
2174
                        }
2175
                }
2176
                finally {
2177
                        if (method != null)
2178
                                method.releaseConnection();
2179
                }
2180
        }
2181

    
2182
        public FileHeaderDTO createFile(Long userId, Long folderId, String name, String mimeType, long fileSize, String filePath)
2183
                        throws DuplicateNameException, ObjectNotFoundException, GSSIOException,
2184
                        InsufficientPermissionsException, QuotaExceededException {
2185
                // Validate.
2186
                if (userId == null)
2187
                        throw new ObjectNotFoundException("No user specified");
2188
                if (folderId == null)
2189
                        throw new ObjectNotFoundException("No folder specified");
2190
                String contentType = mimeType;
2191
                if (StringUtils.isEmpty(mimeType))
2192
                        contentType = DEFAULT_MIME_TYPE;
2193
                if (StringUtils.isEmpty(name))
2194
                        throw new ObjectNotFoundException("No file name specified");
2195
                if (dao.existsFolderOrFile(folderId, name))
2196
                        throw new DuplicateNameException("A folder or file with the name '" + name +
2197
                                                "' already exists at this level");
2198

    
2199
                // Do the actual work.
2200
                Folder parent = null;
2201
                try {
2202
                        parent = dao.getEntityById(Folder.class, folderId);
2203
                } catch (final ObjectNotFoundException onfe) {
2204
                        // Supply a more accurate problem description.
2205
                        throw new ObjectNotFoundException("Parent folder not found");
2206
                }
2207
                final User owner = dao.getEntityById(User.class, userId);
2208
                if (!parent.hasWritePermission(owner))
2209
                        throw new InsufficientPermissionsException("You don't have the permissions to write to this folder");
2210
                final FileHeader file = new FileHeader();
2211
                file.setName(name);
2212
                parent.addFile(file);
2213
                // set file owner to folder owner
2214
                file.setOwner(parent.getOwner());
2215

    
2216
                final Date now = new Date();
2217
                final AuditInfo auditInfo = new AuditInfo();
2218
                auditInfo.setCreatedBy(owner);
2219
                auditInfo.setCreationDate(now);
2220
                auditInfo.setModifiedBy(owner);
2221
                auditInfo.setModificationDate(now);
2222
                file.setAuditInfo(auditInfo);
2223
                // TODO set the proper versioning flag on creation
2224
                file.setVersioned(false);
2225

    
2226
                for (final Permission p : parent.getPermissions()) {
2227
                        final Permission permission = new Permission();
2228
                        permission.setGroup(p.getGroup());
2229
                        permission.setUser(p.getUser());
2230
                        permission.setRead(p.getRead());
2231
                        permission.setWrite(p.getWrite());
2232
                        permission.setModifyACL(p.getModifyACL());
2233
                        file.addPermission(permission);
2234
                }
2235

    
2236
                // Create the file body.
2237
                try {
2238
                        createFileBody(name, contentType, fileSize, filePath, file, auditInfo);
2239
                } catch (FileNotFoundException e) {
2240
                        throw new GSSIOException(e);
2241
                }
2242
                dao.flush();
2243
                indexFile(file.getId(), false);
2244

    
2245
                return file.getDTO();
2246
        }
2247

    
2248
        /* (non-Javadoc)
2249
         * @see gr.ebs.gss.server.ejb.ExternalAPI#updateFileContents(java.lang.Long, java.lang.Long, java.lang.String, java.io.InputStream)
2250
         */
2251
        public FileHeaderDTO updateFileContents(Long userId, Long fileId, String mimeType, long fileSize, String filePath) throws ObjectNotFoundException, GSSIOException, InsufficientPermissionsException, QuotaExceededException {
2252
                if (userId == null)
2253
                        throw new ObjectNotFoundException("No user specified");
2254
                if (fileId == null)
2255
                        throw new ObjectNotFoundException("No file specified");
2256
                String contentType = mimeType;
2257

    
2258
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2259

    
2260
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2261
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2262
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2263
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2264
                        contentType = identifyMimeType(file.getName());
2265

    
2266
                final User owner = dao.getEntityById(User.class, userId);
2267
                if (!file.hasWritePermission(owner))
2268
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2269
                final Date now = new Date();
2270
                final AuditInfo auditInfo = new AuditInfo();
2271
                auditInfo.setCreatedBy(owner);
2272
                auditInfo.setCreationDate(now);
2273
                auditInfo.setModifiedBy(owner);
2274
                auditInfo.setModificationDate(now);
2275
                try {
2276
                        createFileBody(file.getName(), contentType, fileSize, filePath, file, auditInfo);
2277
                } catch (FileNotFoundException e) {
2278
                        throw new GSSIOException(e);
2279
                }
2280

    
2281
                indexFile(fileId, false);
2282
                return file.getDTO();
2283
        }
2284

    
2285
        /**
2286
         * Helper method for identifying mime type by examining the filename extension
2287
         *
2288
         * @param filename
2289
         * @return the mime type
2290
         */
2291
        private String identifyMimeType(String filename) {
2292
                if (filename.indexOf('.') != -1) {
2293
                        String extension = filename.substring(filename.lastIndexOf('.')).toLowerCase(Locale.ENGLISH);
2294
                        if (".doc".equals(extension))
2295
                                return "application/msword";
2296
                        else if (".xls".equals(extension))
2297
                                return "application/vnd.ms-excel";
2298
                        else if (".ppt".equals(extension))
2299
                                return "application/vnd.ms-powerpoint";
2300
                        else if (".pdf".equals(extension))
2301
                                return "application/pdf";
2302
                        else if (".gif".equals(extension))
2303
                                return "image/gif";
2304
                        else if (".jpg".equals(extension) || ".jpeg".equals(extension) || ".jpe".equals(extension))
2305
                                return "image/jpeg";
2306
                        else if (".tiff".equals(extension) || ".tif".equals(extension))
2307
                                return "image/tiff";
2308
                        else if (".png".equals(extension))
2309
                                return "image/png";
2310
                        else if (".bmp".equals(extension))
2311
                                return "image/bmp";
2312
                }
2313
                // when all else fails assign the default mime type
2314
                return DEFAULT_MIME_TYPE;
2315
        }
2316

    
2317
        /**
2318
         * Helper method to create a new file body and attach it as the current body
2319
         * of the provided file header.
2320
         *
2321
         * @param name the original file name
2322
         * @param mimeType the content type
2323
         * @param fileSize the uploaded file size
2324
         * @param filePath the uploaded file full path
2325
         * @param header the file header that will be associated with the new body
2326
         * @param auditInfo the audit info
2327
         * @param owner the owner of the file
2328
         * @throws FileNotFoundException
2329
         * @throws QuotaExceededException
2330
         */
2331
        private void createFileBody(String name, String mimeType, long fileSize, String filePath,
2332
                                FileHeader header, AuditInfo auditInfo)
2333
                        throws FileNotFoundException, QuotaExceededException {
2334

    
2335
                long currentTotalSize = 0;
2336
                if (!header.isVersioned() && header.getCurrentBody() != null && header.getBodies() != null)
2337
                        currentTotalSize = header.getTotalSize();
2338
                Long quotaLeft = getQuotaLeft(header.getOwner().getId());
2339
                if(quotaLeft < fileSize-currentTotalSize) {
2340
                        // quota exceeded -> delete the file
2341
                        deleteActualFile(filePath);
2342
                        throw new QuotaExceededException("Not enough free space available");
2343
                }
2344

    
2345
                FileBody body = new FileBody();
2346

    
2347
                // if no mime type or the generic mime type is defined by the client, then try to identify it from the filename extension
2348
                if (StringUtils.isEmpty(mimeType) || "application/octet-stream".equals(mimeType)
2349
                                        || "application/download".equals(mimeType) || "application/force-download".equals(mimeType)
2350
                                        || "octet/stream".equals(mimeType) || "application/unknown".equals(mimeType))
2351
                        body.setMimeType(identifyMimeType(name));
2352
                else
2353
                        body.setMimeType(mimeType);
2354
                body.setAuditInfo(auditInfo);
2355
                body.setFileSize(fileSize);
2356
                body.setOriginalFilename(name);
2357
                body.setStoredFilePath(filePath);
2358
                //CLEAR OLD VERSION IF FILE IS NOT VERSIONED AND GETS UPDATED
2359
                if(!header.isVersioned() && header.getCurrentBody() != null){
2360
                        header.setCurrentBody(null);
2361
                        if (header.getBodies() != null) {
2362
                                Iterator<FileBody> it = header.getBodies().iterator();
2363
                                while(it.hasNext()){
2364
                                        FileBody bo = it.next();
2365
                                        deleteActualFile(bo.getStoredFilePath());
2366
                                        it.remove();
2367
                                        dao.delete(bo);
2368
                                }
2369
                        }
2370
                }
2371

    
2372
                dao.flush();
2373
                header.addBody(body);
2374

    
2375
                dao.create(body);
2376
        }
2377

    
2378

    
2379
        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
2380
        public File uploadFile(InputStream stream, Long userId) throws IOException, ObjectNotFoundException {
2381
                if (userId == null)
2382
                        throw new ObjectNotFoundException("No user specified");
2383
                User owner = dao.getEntityById(User.class, userId);
2384
                if(owner == null)
2385
                        throw new ObjectNotFoundException("No user specified");
2386
                long start = 0, end = 0;
2387
                if (logger.isDebugEnabled())
2388
                        start = System.currentTimeMillis();
2389
                File result = new File(generateRepositoryFilePath());
2390
                try {
2391
                        final FileOutputStream output = new FileOutputStream(result);
2392
                        final byte[] buffer = new byte[UPLOAD_BUFFER_SIZE];
2393
                        int n = 0;
2394

    
2395
                        while (-1 != (n = stream.read(buffer)))
2396
                                output.write(buffer, 0, n);
2397
                        output.close();
2398
                        stream.close();
2399
                } catch (IOException e) {
2400
                        if (!result.delete())
2401
                                logger.warn("Could not delete " + result.getPath());
2402
                        throw e;
2403
                }
2404
                if (logger.isDebugEnabled()) {
2405
                        end = System.currentTimeMillis();
2406
                        logger.debug("Time to upload: " + (end - start) + " (msec)");
2407
                }
2408
                return result;
2409
        }
2410

    
2411

    
2412
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2413

    
2414
                if (userId == null)
2415
                        throw new ObjectNotFoundException("No user specified");
2416
                User user = dao.getEntityById(User.class, userId);
2417
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2418
                if(status == null){
2419
                        status = new FileUploadStatus();
2420
                        status.setOwner(user);
2421
                        status.setFilename(filename);
2422
                        status.setBytesUploaded(bytesTransfered);
2423
                        status.setFileSize(fileSize);
2424
                        dao.create(status);
2425
                }
2426
                else{
2427
                        status.setBytesUploaded(bytesTransfered);
2428
                        status.setFileSize(fileSize);
2429
                        dao.update(status);
2430
                }
2431

    
2432
        }
2433

    
2434
        public void removeFileUploadProgress(Long userId, String filename) throws ObjectNotFoundException{
2435
                if (userId == null)
2436
                        throw new ObjectNotFoundException("No user specified");
2437
                FileUploadStatus status = dao.getFileUploadStatus(userId, filename);
2438
                if(status != null)
2439
                        dao.delete(status);
2440
        }
2441

    
2442
        @Override
2443
        public FileUploadStatus getFileUploadStatus(Long userId, String fileName) {
2444
                return dao.getFileUploadStatus(userId, fileName);
2445
        }
2446

    
2447
        @Override
2448
        public FolderDTO getFolderWithSubfolders(Long userId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2449
                if (userId == null)
2450
                        throw new ObjectNotFoundException("No user specified");
2451
                if (folderId == null)
2452
                        throw new ObjectNotFoundException("No folder specified");
2453
                final User user = dao.getEntityById(User.class, userId);
2454
                final Folder folder = dao.getEntityById(Folder.class, folderId);
2455
                // Check permissions
2456
                if (!folder.hasReadPermission(user))
2457
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2458
                List<FolderDTO> subfolders = new ArrayList<FolderDTO>();
2459
                if (folder.hasReadPermission(user))
2460
                        for (Folder f : folder.getSubfolders())
2461
                                if (f.hasReadPermission(user) && !f.isDeleted())
2462
                                        subfolders.add(f.getDTO());
2463
                FolderDTO result = folder.getDTO();
2464
                result.setSubfolders(subfolders);
2465
                return folder.getDTO();
2466
        }
2467

    
2468
        @Override
2469
        public FolderDTO getFolderWithSubfolders(Long userId, Long callingUserId, Long folderId) throws ObjectNotFoundException, InsufficientPermissionsException {
2470
                if (userId == null)
2471
                        throw new ObjectNotFoundException("No user specified");
2472
                if (folderId == null)
2473
                        throw new ObjectNotFoundException("No folder specified");
2474
                User user = dao.getEntityById(User.class, callingUserId);
2475
                Folder folder = dao.getEntityById(Folder.class, folderId);
2476
                // Check permissions
2477
                if (!folder.hasReadPermission(user))
2478
                        throw new InsufficientPermissionsException("You don't have the permissions to read this folder");
2479

    
2480
                FolderDTO result = folder.getDTO();
2481
                result.setSubfolders(getSharedSubfolders(userId, callingUserId, folder.getId()));
2482
                return result;
2483
        }
2484

    
2485
        @Override
2486
        public FileBodyDTO getFileVersion(Long userId, Long fileId, int version)
2487
                        throws ObjectNotFoundException, InsufficientPermissionsException {
2488
                if (userId == null)
2489
                        throw new ObjectNotFoundException("No user specified");
2490
                if (fileId == null)
2491
                        throw new ObjectNotFoundException("No file specified");
2492
                if (version < 1)
2493
                        throw new ObjectNotFoundException("No valid version specified");
2494
                User user = dao.getEntityById(User.class, userId);
2495
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2496
                if (!file.hasReadPermission(user) && !file.getFolder().hasReadPermission(user))
2497
                        throw new InsufficientPermissionsException("You don't have the necessary permissions");
2498
                FileBody body = dao.getFileVersion(fileId, version);
2499
                return body.getDTO();
2500
        }
2501

    
2502
        @Override
2503
        public User updateUserPolicyAcceptance(Long userId, boolean isAccepted) throws ObjectNotFoundException {
2504
                if (userId == null)
2505
                        throw new ObjectNotFoundException("No user specified");
2506
                User user = dao.getEntityById(User.class, userId);
2507
                user.setAcceptedPolicy(isAccepted);
2508
                return user;
2509
        }
2510

    
2511
        @Override
2512
        public void updateAccounting(User user, Date date, long bandwidthDiff) {
2513
                dao.updateAccounting(user, date, bandwidthDiff);
2514
        }
2515

    
2516
        @Override
2517
        public boolean canReadFolder(Long userId, Long folderId) throws ObjectNotFoundException {
2518
                if (userId == null)
2519
                        throw new ObjectNotFoundException("No user specified");
2520
                if (folderId == null)
2521
                        throw new ObjectNotFoundException("No folder specified");
2522
                User user = dao.getEntityById(User.class, userId);
2523
                Folder folder = dao.getEntityById(Folder.class, folderId);
2524
                // Check permissions
2525
                if (!folder.hasReadPermission(user))
2526
                        return false;
2527
                return true;
2528
        }
2529

    
2530
        /**
2531
         * Reset WebDAV password for given user.
2532
         *
2533
         * @param userId
2534
         * @return the new password
2535
         * @throws ObjectNotFoundException
2536
         */
2537
        @Override
2538
        public String resetWebDAVPassword(Long userId) throws ObjectNotFoundException {
2539
                if (userId == null)
2540
                        throw new ObjectNotFoundException("No user specified");
2541
                User user = dao.getEntityById(User.class, userId);
2542
                user.generateWebDAVPassword();
2543
                return user.getWebDAVPassword();
2544
        }
2545

    
2546
}