1 package de.dlr.shepard.data.file.services;
2
3 import static com.mongodb.client.model.Filters.eq;
4
5 import com.mongodb.client.MongoCollection;
6 import com.mongodb.client.MongoDatabase;
7 import com.mongodb.client.gridfs.GridFSBucket;
8 import com.mongodb.client.gridfs.GridFSBuckets;
9 import de.dlr.shepard.common.mongodb.NamedInputStream;
10 import de.dlr.shepard.common.util.DateHelper;
11 import de.dlr.shepard.common.util.UuidHelper;
12 import de.dlr.shepard.data.file.entities.ShepardFile;
13 import io.quarkus.logging.Log;
14 import jakarta.enterprise.context.RequestScoped;
15 import jakarta.inject.Inject;
16 import jakarta.inject.Named;
17 import jakarta.ws.rs.InternalServerErrorException;
18 import jakarta.ws.rs.NotFoundException;
19 import jakarta.xml.bind.DatatypeConverter;
20 import java.io.InputStream;
21 import java.security.DigestInputStream;
22 import java.security.MessageDigest;
23 import java.security.NoSuchAlgorithmException;
24 import org.bson.Document;
25 import org.bson.types.ObjectId;
26
27 @RequestScoped
28 public class FileService {
29
30 private static final int CHUNK_SIZE_BYTES = 1024 * 1024;
31 private static final String ID_ATTR = "_id";
32 private static final String FILENAME_ATTR = "name";
33 private static final String FILEID_ATTR = "FileMongoId";
34 private static final String CREATEDAT_ATTR = "createdAt";
35 private static final String MD5_ATTR = "md5";
36
37 @Inject
38 @Named("mongoDatabase")
39 MongoDatabase mongoDatabase;
40
41 @Inject
42 UuidHelper uuidHelper;
43
44 @Inject
45 DateHelper dateHelper;
46
47 public String createFileContainer() {
48 String oid = "FileContainer" + uuidHelper.getUUID().toString();
49 mongoDatabase.createCollection(oid);
50 return oid;
51 }
52
53
54
55
56
57
58
59
60
61 public ShepardFile createFile(String mongoId, String fileName, InputStream inputStream) {
62 MongoCollection<Document> collection;
63 try {
64 collection = mongoDatabase.getCollection(mongoId);
65 } catch (IllegalArgumentException e) {
66 throw new MongoContainerNotFound(mongoId);
67 }
68
69 MessageDigest md;
70 try {
71 md = MessageDigest.getInstance("MD5");
72 } catch (NoSuchAlgorithmException e) {
73 String errorMsg = "No Such Algorithm while uploading file";
74 Log.error(errorMsg);
75 throw new InternalServerErrorException(errorMsg);
76 }
77
78 DigestInputStream dis = new DigestInputStream(inputStream, md);
79 String fileMongoId = createBucket()
80 .withChunkSizeBytes(CHUNK_SIZE_BYTES)
81 .uploadFromStream(fileName, dis)
82 .toHexString();
83 var file = new ShepardFile(dateHelper.getDate(), fileName, DatatypeConverter.printHexBinary(md.digest()));
84 var doc = toDocument(file).append(FILEID_ATTR, fileMongoId);
85 collection.insertOne(doc);
86 file.setOid(doc.getObjectId(ID_ATTR).toHexString());
87 return file;
88 }
89
90
91
92
93
94
95
96
97
98 public NamedInputStream getPayload(String containerId, String fileOid) {
99 MongoCollection<Document> collection;
100 try {
101 collection = mongoDatabase.getCollection(containerId);
102 } catch (IllegalArgumentException e) {
103 throw new MongoContainerNotFound(containerId);
104 }
105 var oid = new ObjectId(fileOid);
106 var payloadDocument = collection.find(eq(ID_ATTR, oid)).first();
107 if (payloadDocument == null) {
108 String errorMsg = "Could not find document with oid: %s".formatted(fileOid);
109 Log.error(errorMsg);
110 throw new NotFoundException(errorMsg);
111 }
112 var fileId = new ObjectId(payloadDocument.getString(FILEID_ATTR));
113 var filename = payloadDocument.getString(FILENAME_ATTR);
114 var gridBucket = createBucket();
115 var gridFsFile = gridBucket.find(eq(ID_ATTR, fileId)).first();
116 if (gridFsFile == null) throw new NotFoundException("File %s does not exist in MongoDB bucket!".formatted(fileOid));
117 var inputStream = gridBucket.openDownloadStream(fileId);
118
119 return new NamedInputStream(fileOid, inputStream, filename, gridFsFile.getLength());
120 }
121
122
123
124
125
126
127
128
129
130 public ShepardFile getFile(String containerId, String fileOid) {
131 MongoCollection<Document> collection;
132 try {
133 collection = mongoDatabase.getCollection(containerId);
134 } catch (IllegalArgumentException e) {
135 throw new MongoContainerNotFound(containerId);
136 }
137 var doc = collection.find(eq(ID_ATTR, new ObjectId(fileOid))).first();
138 if (doc == null) {
139 String errorMsg = "Could not find file with oid: %s".formatted(fileOid);
140 Log.error(errorMsg);
141 throw new NotFoundException(errorMsg);
142 }
143 return toShepardFile(doc);
144 }
145
146
147
148
149
150 public void deleteFileContainer(String mongoId) {
151 MongoCollection<Document> toDelete;
152 try {
153 toDelete = mongoDatabase.getCollection(mongoId);
154 } catch (IllegalArgumentException e) {
155 String errorMsg = "Could not delete container with mongoid: %s".formatted(mongoId);
156 Log.error(errorMsg);
157 throw new NotFoundException(errorMsg);
158 }
159 GridFSBucket gridBucket = createBucket();
160 for (Document doc : toDelete.find()) {
161 gridBucket.delete(new ObjectId(doc.getString(FILEID_ATTR)));
162 }
163 toDelete.drop();
164 }
165
166 public void deleteFile(String mongoId, String fileOid) {
167 MongoCollection<Document> collection;
168 try {
169 collection = mongoDatabase.getCollection(mongoId);
170 } catch (IllegalArgumentException e) {
171 throw new MongoContainerNotFound(mongoId);
172 }
173 var doc = collection.findOneAndDelete(eq(ID_ATTR, new ObjectId(fileOid)));
174 if (doc == null) {
175 String errorMsg = "Could not find and delete file with oid: %s".formatted(fileOid);
176 Log.error(errorMsg);
177 throw new NotFoundException(errorMsg);
178 }
179 var gridBucket = createBucket();
180 gridBucket.delete(new ObjectId(doc.getString(FILEID_ATTR)));
181 }
182
183 private static ShepardFile toShepardFile(Document doc) {
184 var file = new ShepardFile(
185 doc.getObjectId(ID_ATTR).toHexString(),
186 doc.getDate(CREATEDAT_ATTR),
187 doc.getString(FILENAME_ATTR),
188 doc.getString(MD5_ATTR)
189 );
190 return file;
191 }
192
193 private static Document toDocument(ShepardFile file) {
194 var doc = new Document()
195 .append(CREATEDAT_ATTR, file.getCreatedAt())
196 .append(FILENAME_ATTR, file.getFilename())
197 .append(MD5_ATTR, file.getMd5());
198 if (file.getOid() != null) doc.append(ID_ATTR, new ObjectId(file.getOid()));
199 return doc;
200 }
201
202 private GridFSBucket createBucket() {
203 return GridFSBuckets.create(mongoDatabase);
204 }
205 }