1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.solr.search;
20
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Enumeration;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.StringTokenizer;
28
29 import org.apache.logging.log4j.LogManager;
30 import org.apache.logging.log4j.Logger;
31 import org.jdom2.Document;
32 import org.jdom2.Element;
33 import org.jdom2.filter.ElementFilter;
34 import org.mycore.common.MCRUsageException;
35 import org.mycore.parsers.bool.MCRAndCondition;
36 import org.mycore.parsers.bool.MCRCondition;
37 import org.mycore.parsers.bool.MCROrCondition;
38 import org.mycore.parsers.bool.MCRSetCondition;
39 import org.mycore.services.fieldquery.MCRQuery;
40 import org.mycore.services.fieldquery.MCRQueryCondition;
41 import org.mycore.services.fieldquery.MCRQueryParser;
42 import org.mycore.services.fieldquery.MCRSortBy;
43
44 import jakarta.servlet.http.HttpServletRequest;
45
46 public class MCRQLSearchUtils {
47
48 private static final Logger LOGGER = LogManager.getLogger(MCRQLSearchUtils.class);
49
50 private static HashSet<String> SEARCH_PARAMETER = new HashSet<>(Arrays.asList("search", "query", "maxResults",
51 "numPerPage", "page", "mask", "mode", "redirect", "qt"));
52
53
54
55
56 public static MCRQuery buildFormQuery(Element root) {
57 Element conditions = root.getChild("conditions");
58
59 if (conditions.getAttributeValue("format", "xml").equals("xml")) {
60 Element condition = conditions.getChildren().get(0);
61 renameElements(condition);
62
63
64 List<Element> empty = new ArrayList<>();
65 for (Iterator<Element> it = conditions.getDescendants(new ElementFilter("condition")); it.hasNext();) {
66 Element cond = it.next();
67 if (cond.getAttribute("value") == null) {
68 empty.add(cond);
69 }
70 }
71
72
73 Element sortBy = root.getChild("sortBy");
74 if (sortBy != null) {
75 for (Element field : sortBy.getChildren("field")) {
76 if (field.getAttributeValue("name", "").length() == 0) {
77 empty.add(field);
78 }
79 }
80 }
81
82 for (int i = empty.size() - 1; i >= 0; i--) {
83 empty.get(i).detach();
84 }
85
86 if (sortBy != null && sortBy.getChildren().size() == 0) {
87 sortBy.detach();
88 }
89
90
91 Element returnFields = root.getChild("returnFields");
92 if (returnFields != null && returnFields.getText().length() == 0) {
93 returnFields.detach();
94 }
95 }
96
97 return MCRQuery.parseXML(root.getDocument());
98 }
99
100
101
102
103 protected static void renameElements(Element element) {
104 if (element.getName().startsWith("condition")) {
105 element.setName("condition");
106
107 String field = new StringTokenizer(element.getAttributeValue("field"), " -,").nextToken();
108 String operator = element.getAttributeValue("operator");
109 if (operator == null) {
110 LOGGER.warn("No operator defined for field: {}", field);
111 operator = "=";
112 }
113 element.setAttribute("operator", operator);
114
115 List<Element> values = element.getChildren("value");
116 if (values != null && values.size() > 0) {
117 element.removeAttribute("field");
118 element.setAttribute("operator", "or");
119 element.setName("boolean");
120 for (Element value : values) {
121 value.setName("condition");
122 value.setAttribute("field", field);
123 value.setAttribute("operator", operator);
124 value.setAttribute("value", value.getText());
125 value.removeContent();
126 }
127 }
128 } else if (element.getName().startsWith("boolean")) {
129 element.setName("boolean");
130 for (Object child : element.getChildren()) {
131 if (child instanceof Element) {
132 renameElements((Element) child);
133 }
134 }
135 }
136 }
137
138
139
140
141 public static MCRQuery buildComplexQuery(String query) {
142 return new MCRQuery(new MCRQueryParser().parse(query));
143 }
144
145
146
147
148 @SuppressWarnings({ "rawtypes", "unchecked" })
149 public static MCRQuery buildDefaultQuery(String search, String defaultSearchField) {
150 String[] fields = defaultSearchField.split(" *, *");
151 MCROrCondition queryCondition = new MCROrCondition();
152
153 for (String fDef : fields) {
154 MCRCondition condition = new MCRQueryCondition(fDef, "=", search);
155 queryCondition.addChild(condition);
156 }
157
158 return new MCRQuery(MCRQueryParser.normalizeCondition(queryCondition));
159 }
160
161
162
163
164 @SuppressWarnings({ "rawtypes", "unchecked" })
165 public static MCRQuery buildNameValueQuery(HttpServletRequest req) {
166 MCRAndCondition condition = new MCRAndCondition();
167
168 for (Enumeration<String> names = req.getParameterNames(); names.hasMoreElements();) {
169 String name = names.nextElement();
170 if (name.endsWith(".operator")) {
171 continue;
172 }
173 if (name.contains(".sortField")) {
174 continue;
175 }
176 if (SEARCH_PARAMETER.contains(name)) {
177 continue;
178 }
179 if (name.startsWith("XSL.")) {
180 continue;
181 }
182
183 String[] values = req.getParameterValues(name);
184 MCRSetCondition parent = condition;
185
186 if ((values.length > 1) || name.contains(",")) {
187
188 parent = new MCROrCondition();
189 condition.addChild(parent);
190 }
191
192 for (String fieldName : name.split(",")) {
193 String operator = getReqParameter(req, fieldName + ".operator", "=");
194 for (String value : values) {
195 parent.addChild(new MCRQueryCondition(fieldName, operator, value));
196 }
197 }
198 }
199
200 if (condition.getChildren().isEmpty()) {
201 throw new MCRUsageException("Missing query condition");
202 }
203
204 return new MCRQuery(MCRQueryParser.normalizeCondition(condition));
205 }
206
207 protected static Document setQueryOptions(MCRQuery query, HttpServletRequest req) {
208 String maxResults = getReqParameter(req, "maxResults", "0");
209 query.setMaxResults(Integer.parseInt(maxResults));
210
211 List<String> sortFields = new ArrayList<>();
212 for (Enumeration<String> names = req.getParameterNames(); names.hasMoreElements();) {
213 String name = names.nextElement();
214 if (name.contains(".sortField")) {
215 sortFields.add(name);
216 }
217 }
218
219 if (sortFields.size() > 0) {
220 sortFields.sort((arg0, arg1) -> {
221 String s0 = arg0.substring(arg0.indexOf(".sortField"));
222 String s1 = arg1.substring(arg1.indexOf(".sortField"));
223 return s0.compareTo(s1);
224 });
225 List<MCRSortBy> sortBy = new ArrayList<>();
226 for (String name : sortFields) {
227 String sOrder = getReqParameter(req, name, "ascending");
228 boolean order = "ascending".equals(sOrder) ? MCRSortBy.ASCENDING : MCRSortBy.DESCENDING;
229 String fieldName = name.substring(0, name.indexOf(".sortField"));
230 sortBy.add(new MCRSortBy(fieldName, order));
231 }
232 query.setSortBy(sortBy);
233 }
234
235 Document xml = query.buildXML();
236 xml.getRootElement().setAttribute("numPerPage", getReqParameter(req, "numPerPage", "0"));
237 xml.getRootElement().setAttribute("mask", getReqParameter(req, "mask", "-"));
238 return xml;
239 }
240
241 protected static String getReqParameter(HttpServletRequest req, String name, String defaultValue) {
242 String value = req.getParameter(name);
243 if (value == null || value.trim().length() == 0) {
244 return defaultValue;
245 } else {
246 return value.trim();
247 }
248 }
249 }