1 package de.dlr.shepard.common.search.services;
2
3 import com.mongodb.client.MongoCollection;
4 import com.mongodb.client.MongoDatabase;
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.InvalidBodyException;
8 import de.dlr.shepard.common.neo4j.io.BasicEntityIO;
9 import de.dlr.shepard.common.search.io.ResponseBody;
10 import de.dlr.shepard.common.search.io.ResultTriple;
11 import de.dlr.shepard.common.search.io.SearchBody;
12 import de.dlr.shepard.common.search.io.SearchScope;
13 import de.dlr.shepard.common.search.query.MongoDBQueryBuilder;
14 import de.dlr.shepard.common.util.TraversalRules;
15 import de.dlr.shepard.context.references.basicreference.entities.BasicReference;
16 import de.dlr.shepard.context.references.structureddata.daos.StructuredDataReferenceDAO;
17 import de.dlr.shepard.context.references.structureddata.entities.StructuredDataReference;
18 import de.dlr.shepard.data.structureddata.entities.StructuredData;
19 import jakarta.enterprise.context.RequestScoped;
20 import jakarta.inject.Inject;
21 import jakarta.inject.Named;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import org.bson.Document;
29
30 @RequestScoped
31 public class StructuredDataSearchService {
32
33 @Inject
34 StructuredDataReferenceDAO structuredDataReferenceDAO;
35
36 @Inject
37 UserService userService;
38
39 @Inject
40 @Named("mongoDatabase")
41 MongoDatabase mongoDatabase;
42
43 public ResponseBody search(SearchBody searchBody) {
44 User user = userService.getCurrentUser();
45
46 var reachableReferences = findReachableReferences(searchBody, user.getUsername());
47 var matchingReferences = findMatchingReferences(reachableReferences, searchBody);
48 return getStructuredDataResponse(matchingReferences, searchBody);
49 }
50
51 private ResponseBody getStructuredDataResponse(
52 Map<StructuredDataReference, Long> matchingReferences,
53 SearchBody searchBody
54 ) {
55 BasicReference[] references = matchingReferences.keySet().toArray(new BasicReference[0]);
56 ResultTriple[] resultTriples = new ResultTriple[references.length];
57 BasicEntityIO[] results = new BasicEntityIO[references.length];
58 for (var i = 0; i < references.length; i++) {
59
60 resultTriples[i] = new ResultTriple(
61 matchingReferences.get(references[i]),
62 references[i].getDataObject().getId(),
63 references[i].getId()
64 );
65 results[i] = new BasicEntityIO(references[i]);
66 }
67 ResponseBody responseBody = new ResponseBody(resultTriples, results, searchBody.getSearchParams());
68 return responseBody;
69 }
70
71 private Map<StructuredDataReference, Long> findMatchingReferences(
72 Map<StructuredDataReference, Long> reachableReferences,
73 SearchBody searchBody
74 ) {
75 Map<StructuredDataReference, Long> matchingReferences = new HashMap<>();
76 for (var reference : reachableReferences.entrySet()) {
77 String mongoContainerId = reference.getKey().getStructuredDataContainer().getMongoId();
78 MongoCollection<Document> mongoContainer = mongoDatabase.getCollection(mongoContainerId);
79 List<String> mongoStructuredDataIds = new ArrayList<>();
80 for (StructuredData structuredData : reference.getKey().getStructuredDatas()) {
81 mongoStructuredDataIds.add(makeMongoQueryId(structuredData.getOid()));
82 }
83 String mongoQuery = "{_id: {$in: " + makeMongoQueryArray(mongoStructuredDataIds) + "}";
84 String mongoSearchQuery = searchBody.getSearchParams().getQuery();
85
86
87
88 if (mongoSearchQuery.startsWith("{")) mongoSearchQuery = MongoDBQueryBuilder.getMongoDBQueryString(
89 mongoSearchQuery
90 );
91 mongoQuery += ", " + mongoSearchQuery + "}";
92 var mongoQueryDocument = Document.parse(mongoQuery);
93 var mongoQueryResult = mongoContainer.find(mongoQueryDocument);
94 if (mongoQueryResult.first() != null) matchingReferences.put(reference.getKey(), reference.getValue());
95 }
96 return matchingReferences;
97 }
98
99 private Map<StructuredDataReference, Long> findReachableReferences(SearchBody searchBody, String userName) {
100 Map<StructuredDataReference, Long> ret = new HashMap<>();
101 for (SearchScope searchScope : searchBody.getScopes()) findReachableReferenceFromScope(
102 searchScope,
103 userName
104 ).forEach(r -> ret.put(r, searchScope.getCollectionId()));
105 return ret;
106 }
107
108 private Set<StructuredDataReference> findReachableReferenceFromScope(SearchScope searchScope, String userName) {
109 Set<StructuredDataReference> ret = new HashSet<>();
110 TraversalRules[] traversalRules = searchScope.getTraversalRules();
111 Long collectionShepardId = searchScope.getCollectionId();
112 if (collectionShepardId == null) {
113 throw new InvalidBodyException("Collection is necessary");
114 }
115
116 if (searchScope.getDataObjectId() == null) {
117 ret.addAll(structuredDataReferenceDAO.findReachableReferencesByNeo4jId(collectionShepardId, userName));
118 }
119
120 else {
121 long startShepardId = searchScope.getDataObjectId();
122
123 if (traversalRules.length == 0) {
124 List<StructuredDataReference> reachableReferences = structuredDataReferenceDAO.findReachableReferencesByNeo4jId(
125 collectionShepardId,
126 startShepardId,
127 userName
128 );
129 ret.addAll(reachableReferences);
130 }
131
132 else {
133 for (TraversalRules traversalRule : traversalRules) {
134 List<StructuredDataReference> reachableReferences =
135 structuredDataReferenceDAO.findReachableReferencesByNeo4jId(
136 traversalRule,
137 collectionShepardId,
138 startShepardId,
139 userName
140 );
141 ret.addAll(reachableReferences);
142 }
143 }
144 }
145 return ret;
146 }
147
148 private static String makeMongoQueryId(String mongoId) {
149 return "{$oid: '" + mongoId + "'}";
150 }
151
152 private static String makeMongoQueryArray(List<String> strings) {
153 return "[" + String.join(", ", strings) + "]";
154 }
155 }