View Javadoc
1   package de.dlr.shepard.context.references.file.services;
2   
3   import de.dlr.shepard.auth.permission.services.PermissionsService;
4   import de.dlr.shepard.auth.security.AuthenticationContext;
5   import de.dlr.shepard.auth.users.entities.User;
6   import de.dlr.shepard.auth.users.services.UserService;
7   import de.dlr.shepard.common.exceptions.InvalidAuthException;
8   import de.dlr.shepard.common.exceptions.InvalidBodyException;
9   import de.dlr.shepard.common.exceptions.InvalidPathException;
10  import de.dlr.shepard.common.exceptions.InvalidRequestException;
11  import de.dlr.shepard.common.mongoDB.NamedInputStream;
12  import de.dlr.shepard.common.util.DateHelper;
13  import de.dlr.shepard.context.collection.services.CollectionService;
14  import de.dlr.shepard.context.collection.services.DataObjectService;
15  import de.dlr.shepard.context.references.IReferenceService;
16  import de.dlr.shepard.context.references.file.daos.FileReferenceDAO;
17  import de.dlr.shepard.context.references.file.entities.FileReference;
18  import de.dlr.shepard.context.references.file.io.FileReferenceIO;
19  import de.dlr.shepard.context.version.services.VersionService;
20  import de.dlr.shepard.data.file.daos.ShepardFileDAO;
21  import de.dlr.shepard.data.file.entities.FileContainer;
22  import de.dlr.shepard.data.file.entities.ShepardFile;
23  import de.dlr.shepard.data.file.services.FileContainerService;
24  import de.dlr.shepard.data.file.services.FileService;
25  import io.quarkus.logging.Log;
26  import jakarta.enterprise.context.RequestScoped;
27  import jakarta.inject.Inject;
28  import jakarta.ws.rs.NotFoundException;
29  import java.util.ArrayList;
30  import java.util.List;
31  import java.util.UUID;
32  
33  @RequestScoped
34  public class FileReferenceService implements IReferenceService<FileReference, FileReferenceIO> {
35  
36    @Inject
37    FileReferenceDAO fileReferenceDAO;
38  
39    @Inject
40    DataObjectService dataObjectService;
41  
42    @Inject
43    FileContainerService fileContainerService;
44  
45    @Inject
46    ShepardFileDAO fileDAO;
47  
48    @Inject
49    VersionService versionService;
50  
51    @Inject
52    DateHelper dateHelper;
53  
54    @Inject
55    FileService fileService;
56  
57    @Inject
58    PermissionsService permissionsService;
59  
60    @Inject
61    CollectionService collectionService;
62  
63    @Inject
64    AuthenticationContext authenticationContext;
65  
66    @Inject
67    UserService userService;
68  
69    /**
70     * Gets FileReference list for a given dataobject.
71     *
72     * @param collectionShepardId
73     * @param dataObjectShepardId
74     * @param versionUID the version UUID
75     * @return List<FileReference>
76     * @throws InvalidPathException If collection or dataobject cannot be found, or no association between dataobject and collection exists
77     * @throws InvalidAuthException If user has no read permissions on collection or dataobject specified by request path
78     */
79    @Override
80    public List<FileReference> getAllReferencesByDataObjectId(
81      long collectionShepardId,
82      long dataObjectShepardId,
83      UUID versionUID
84    ) {
85      dataObjectService.getDataObject(collectionShepardId, dataObjectShepardId, versionUID);
86  
87      List<FileReference> references = fileReferenceDAO.findByDataObjectShepardId(dataObjectShepardId);
88      return references;
89    }
90  
91    /**
92     * Gets FileReference by shepard id.
93     *
94     * @param collectionShepardId
95     * @param dataObjectShepardId
96     * @param shepardId
97     * @param versionUID the version UUID
98     * @return FileReference
99     * @throws InvalidPathException If reference with Id does not exist or is deleted, or if collection or dataObject Id of path is not valid
100    * @throws InvalidAuthException If user has no read permissions on collection or dataobject specified by request path
101    */
102   @Override
103   public FileReference getReference(
104     long collectionShepardId,
105     long dataObjectShepardId,
106     long shepardId,
107     UUID versionUID
108   ) {
109     dataObjectService.getDataObject(collectionShepardId, dataObjectShepardId, versionUID);
110 
111     FileReference fileReference = fileReferenceDAO.findByShepardId(shepardId, versionUID);
112     if (fileReference == null || fileReference.isDeleted()) {
113       String errorMsg = String.format("ID ERROR - File Reference with id %s is null or deleted", shepardId);
114       Log.error(errorMsg);
115       throw new InvalidPathException(errorMsg);
116     }
117 
118     if (
119       fileReference.getDataObject() == null || !fileReference.getDataObject().getShepardId().equals(dataObjectShepardId)
120     ) {
121       String errorMsg = "ID ERROR - There is no association between dataObject and reference";
122       Log.error(errorMsg);
123       throw new InvalidPathException(errorMsg);
124     }
125 
126     return fileReference;
127   }
128 
129   /**
130    * Creates a new FileReference
131    *
132    * @param collectionShepardId
133    * @param dataObjectShepardId DataObject id for the reference to be created
134    * @param fileReference Reference object
135    * @return FileReference
136    * @throws InvalidPathException if collection or dataobject specified by their Ids are null or deleted
137    * @throws InvalidAuthException if user has no permission to edit referencing collection or no read permissions on referenced container
138    */
139   @Override
140   public FileReference createReference(
141     long collectionShepardId,
142     long dataObjectShepardId,
143     FileReferenceIO fileReference
144   ) {
145     var dataObject = dataObjectService.getDataObject(collectionShepardId, dataObjectShepardId);
146     collectionService.assertIsAllowedToEditCollection(collectionShepardId);
147 
148     User user = userService.getCurrentUser();
149 
150     FileContainer container;
151     try {
152       container = fileContainerService.getContainer(fileReference.getFileContainerId());
153     } catch (InvalidPathException | InvalidAuthException ex) {
154       Log.error(ex.getMessage());
155       throw new InvalidBodyException(ex.getMessage());
156     }
157 
158     var toCreate = new FileReference();
159     toCreate.setCreatedAt(dateHelper.getDate());
160     toCreate.setCreatedBy(user);
161     toCreate.setDataObject(dataObject);
162     toCreate.setName(fileReference.getName());
163     toCreate.setFileContainer(container);
164 
165     // Get existing file
166     for (var oid : fileReference.getFileOids()) {
167       var file = fileDAO.find(container.getId(), oid);
168       if (file != null) {
169         toCreate.addFile(file);
170       } else {
171         Log.warnf("Could not find file with oid: %s", oid);
172       }
173     }
174 
175     var created = fileReferenceDAO.createOrUpdate(toCreate);
176     created.setShepardId(created.getId());
177     created = fileReferenceDAO.createOrUpdate(created);
178     versionService.attachToVersionOfVersionableEntityAndReturnVersion(dataObject.getId(), created.getId());
179     return created;
180   }
181 
182   /**
183    * Deletes the file reference.
184    *
185    * @param collectionShepardId
186    * @param dataObjectShepardId
187    * @param fileReferenceShepardId
188    * @throws InvalidPathException if collection or dataobject specified by their Ids are null or deleted
189    * @throws InvalidAuthException if user has no permissions to edit the collection, which the reference is assigned to
190    */
191   @Override
192   public void deleteReference(long collectionShepardId, long dataObjectShepardId, long fileReferenceShepardId) {
193     FileReference fileReference = getReference(collectionShepardId, dataObjectShepardId, fileReferenceShepardId, null);
194     collectionService.assertIsAllowedToEditCollection(collectionShepardId);
195 
196     User user = userService.getCurrentUser();
197     fileReference.setDeleted(true);
198     fileReference.setUpdatedBy(user);
199     fileReference.setUpdatedAt(dateHelper.getDate());
200     fileReferenceDAO.createOrUpdate(fileReference);
201   }
202 
203   /**
204    * Returns list of ShepardFile.
205    *
206    * @param collectionShepardId
207    * @param dataObjectShepardId
208    * @param fileReferenceShepardId identifies the file reference
209    * @param versionUID
210    * @return list of shepard files
211    * @throws InvalidPathException if collection, dataobject or reference specified by their Ids are null or deleted
212    */
213   public List<ShepardFile> getFiles(
214     long collectionShepardId,
215     long dataObjectShepardId,
216     long fileReferenceShepardId,
217     UUID versionUID
218   ) {
219     FileReference reference = getReference(
220       collectionShepardId,
221       dataObjectShepardId,
222       fileReferenceShepardId,
223       versionUID
224     );
225 
226     if (reference.getFileContainer() == null || reference.getFileContainer().isDeleted()) {
227       String errorMsg = String.format(
228         "Referenced FileContainer is not set or deleted in FileReference with id %s",
229         reference.getId()
230       );
231       Log.error(errorMsg);
232       throw new NotFoundException(errorMsg);
233     }
234 
235     try {
236       fileContainerService.getContainer(reference.getFileContainer().getId());
237     } catch (InvalidPathException ex) {
238       Log.error(ex.getMessage());
239       throw new NotFoundException(ex.getMessage());
240     }
241 
242     return reference.getFiles();
243   }
244 
245   /**
246    * Returns a NamedInputStream of the specified file
247    *
248    * @param fileReferenceShepardId identifies the file reference
249    * @param oid identifies the actual file
250    * @param username the current user
251    * @return NamedInputStream
252    * @throws InvalidPathException when FileReference cannot be found due to invalid collection, dataobject or reference Ids
253    * @throws InvalidAuthException when the user is not authorized to access the container
254    * @throws NotFoundException when mongoDb is not able to find document container or file by mongoId or oid, or when Referenced file container is not accessible
255    * @throws InvalidRequestException when FileContainer is not accessible
256    */
257   public NamedInputStream getPayload(
258     long collectionShepardId,
259     long dataObjectShepardId,
260     long fileReferenceShepardId,
261     String oid,
262     UUID versionUID
263   ) {
264     FileReference reference = getReference(
265       collectionShepardId,
266       dataObjectShepardId,
267       fileReferenceShepardId,
268       versionUID
269     );
270 
271     if (reference.getFileContainer() == null || reference.getFileContainer().isDeleted()) {
272       String errorMsg = String.format(
273         "FileContainer with id %s is not set or deleted in FileReference",
274         reference.getFileContainer()
275       );
276       Log.error(errorMsg);
277       throw new NotFoundException(errorMsg);
278     }
279 
280     try {
281       // check that FileContainer is actually accessible and user has permissions to read from it
282       fileContainerService.getContainer(reference.getFileContainer().getId());
283     } catch (InvalidPathException e) {
284       Log.error(e.getMessage());
285       throw new NotFoundException(e.getMessage());
286     }
287 
288     String mongoId = reference.getFileContainer().getMongoId();
289     return fileService.getPayload(mongoId, oid);
290   }
291 
292   /**
293    * Returns a list of NamedInputStreams of all files in that reference
294    *
295    * Returns empty input streams if referenced file container is not accessible.
296    *
297    * @param collectionShepardId
298    * @param dataObjectShepardId
299    * @param fileReferenceShepardId identifies the file reference
300    * @return list of NamedInputStreams
301    * @throws InvalidPathException when FileReference cannot be found due to invalid collection, dataobject or reference Ids
302    * @throws NotFoundException when container is not accessible
303    * @throws InvalidAuthException when the user is not authorized to access the container
304    */
305   public List<NamedInputStream> getAllPayloads(
306     long collectionShepardId,
307     long dataObjectShepardId,
308     long fileReferenceShepardId
309   ) {
310     FileReference reference = getReference(collectionShepardId, dataObjectShepardId, fileReferenceShepardId, null);
311 
312     if (reference.getFileContainer() == null || reference.getFileContainer().isDeleted()) {
313       String errorMsg = String.format(
314         "Referenced FileContainer is not set or deleted in FileReference with id %s",
315         reference.getId()
316       );
317       Log.error(errorMsg);
318       throw new NotFoundException(errorMsg);
319     }
320 
321     try {
322       // check that referenced container is actually accessible
323       fileContainerService.getContainer(reference.getFileContainer().getId());
324     } catch (InvalidPathException ex) {
325       throw new NotFoundException(ex.getMessage());
326     }
327 
328     List<ShepardFile> files = reference.getFiles();
329 
330     var result = new ArrayList<NamedInputStream>(files.size());
331     for (var file : files) {
332       NamedInputStream nis;
333       try {
334         nis = fileService.getPayload(reference.getFileContainer().getMongoId(), file.getOid());
335         result.add(nis);
336       } catch (NotFoundException e) {
337         result.add(new NamedInputStream(file.getOid(), null, file.getFilename(), 0L));
338       }
339     }
340     return result;
341   }
342 }