Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (94.2 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 FolderDTO 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
                return 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
         * @return the new folder
304
         */
305
        private FolderDTO createFolder(String name, Folder parent, User creator) {
306
                Folder folder = new Folder();
307
                folder.setName(name);
308
                if (parent != null) {
309
                        parent.addSubfolder(folder);
310
                        folder.setOwner(parent.getOwner());
311
                } else
312
                        folder.setOwner(creator);
313

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

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

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

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

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

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

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

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

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

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

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

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

    
453
                // TODO: Check permissions
454

    
455
                final User owner = dao.getEntityById(User.class, userId);
456

    
457
                // Do the actual work.
458
                owner.createGroup(name);
459
        }
460

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

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

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

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

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

    
549

    
550

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
928
        }
929

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

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

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

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

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

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

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

    
1017
        }
1018

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

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

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

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

    
1082
                file.setDeleted(true);
1083
                dao.update(file);
1084
        }
1085

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1211
                file.setDeleted(false);
1212
                dao.update(file);
1213
        }
1214

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

    
1232
        }
1233

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1370
        }
1371

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

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

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

    
1429
        }
1430

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

    
1452
        }
1453

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

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

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

    
1496
        }
1497

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

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

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

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

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

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

    
1573
                        dao.update(file);
1574
                }
1575
        }
1576

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

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

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

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

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

    
1641
        }
1642

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

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

    
1679
        }
1680

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

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

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

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

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

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

    
1797

    
1798
        }
1799

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

    
1810
        }
1811

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

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

    
1844
        }
1845

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

    
1854
        }
1855

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

    
1861
        }
1862

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

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

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

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

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

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

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

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

    
1962

    
1963
        }
1964

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

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

    
1984
        }
1985

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

    
2010
        }
2011

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

    
2030
                }
2031
        }
2032

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2247
                return file.getDTO();
2248
        }
2249

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

    
2260
                FileHeader file = dao.getEntityById(FileHeader.class, fileId);
2261

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

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

    
2283
                indexFile(fileId, false);
2284
                return file.getDTO();
2285
        }
2286

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

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

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

    
2347
                FileBody body = new FileBody();
2348

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

    
2374
                dao.flush();
2375
                header.addBody(body);
2376

    
2377
                dao.create(body);
2378
        }
2379

    
2380

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

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

    
2413

    
2414
        public void createFileUploadProgress(Long userId, String filename, Long bytesTransfered, Long fileSize) throws ObjectNotFoundException{
2415

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

    
2434
        }
2435

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

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

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

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

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

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

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

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

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

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

    
2548
}