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