source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/QueryAction.java@ 32448

Last change on this file since 32448 was 32448, checked in by kjdon, 6 years ago

params class changed, now returns false by default for shouldsave. so don't need to add any that we don't want saving in the session. turned hard coded strings into static string variables

  • Property svn:keywords set to Author Date Id Revision
File size: 16.0 KB
Line 
1package org.greenstone.gsdl3.action;
2
3import java.io.Serializable;
4import java.util.HashMap;
5import java.util.HashSet;
6
7import org.apache.log4j.Logger;
8import org.greenstone.gsdl3.util.GSParams;
9import org.greenstone.gsdl3.util.GSPath;
10import org.greenstone.gsdl3.util.GSXML;
11import org.greenstone.gsdl3.util.GSXSLT;
12import org.greenstone.gsdl3.util.UserContext;
13import org.greenstone.gsdl3.util.XMLConverter;
14import org.w3c.dom.Document;
15import org.w3c.dom.Element;
16import org.w3c.dom.Node;
17import org.w3c.dom.NodeList;
18
19/** action class for queries */
20public class QueryAction extends Action
21{
22
23 public static final String HITS_PER_PAGE_ARG = "hitsPerPage";
24 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.QueryAction.class.getName());
25
26 /**
27 * tell the param class what its arguments are.
28 * if an action has its own arguments, this should add them to
29 * the params object - particularly
30 * important for args that need to be saved to the session
31 */
32 public boolean addActionParameters(GSParams params)
33 {
34 // some query services don't do paging themselves, in shich case we do it here. Let tell servlet to save the param just in case nothing else is doing that.
35 params.addServiceParameter(HITS_PER_PAGE_ARG, "20", true, false);
36 return true;
37 }
38
39 /**
40 * process - processes a request.
41 */
42 public Node process(Node message_node)
43 {
44 Element message = GSXML.nodeToElement(message_node);
45 Document doc = message.getOwnerDocument();
46
47 // get the request - assume there is only one
48 Element request = (Element) GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
49
50 // create the return message
51 Element result = doc.createElement(GSXML.MESSAGE_ELEM);
52 Element response = basicQuery(request);
53 result.appendChild(doc.importNode(response, true));
54 return result;
55 }
56
57 /**
58 * a generic query handler this gets the service description, does the query
59 * (just passes all the params to the service, then gets the titles for any
60 * results
61 */
62 protected Element basicQuery(Element request)
63 {
64 // the result
65 Document doc = request.getOwnerDocument();
66 Element page_response = doc.createElement(GSXML.RESPONSE_ELEM);
67
68 // extract the params from the cgi-request, and check that we have a coll specified
69 Element cgi_param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
70 HashMap<String, Serializable> params = GSXML.extractParams(cgi_param_list, false);
71
72 String request_type = (String) params.get(GSParams.REQUEST_TYPE);
73 String service_name = (String) params.get(GSParams.SERVICE);
74 String collection = (String) params.get(GSParams.COLLECTION);
75 String lang = request.getAttribute(GSXML.LANG_ATT);
76 // collection may be null or empty when we are doing cross coll services
77 if (collection == null || collection.equals(""))
78 {
79 collection = null;
80 }
81
82 UserContext userContext = new UserContext(request);
83 String to = service_name;
84 if (collection != null)
85 {
86 to = GSPath.prependLink(to, collection);
87 }
88
89 // get the format info - there may be global format info in the collection that searching needs
90 Element format_elem = getFormatInfo(to, userContext);
91 if (format_elem != null) {
92 // set the format type
93 format_elem.setAttribute(GSXML.TYPE_ATT, "search");
94 // for now just add to the response
95 page_response.appendChild(doc.importNode(format_elem, true));
96 }
97 // get the service description
98 // we have been asked for the service description
99 Element mr_info_message = doc.createElement(GSXML.MESSAGE_ELEM);
100 Element mr_info_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, to, userContext);
101 mr_info_message.appendChild(mr_info_request);
102
103 // process the message
104 Element mr_info_response = (Element) this.mr.process(mr_info_message);
105
106 boolean does_paging = false;
107
108 // the response
109 Element service_response = (Element) GSXML.getChildByTagName(mr_info_response, GSXML.RESPONSE_ELEM);
110
111 Element service_description = (Element)GSXML.getChildByTagName(service_response, GSXML.SERVICE_ELEM);
112 if (service_description != null) {
113 service_description = (Element) doc.importNode(service_description, true);
114
115 Element meta_list =(Element) GSXML.getChildByTagName(service_description, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
116 if (meta_list != null) {
117 String value = GSXML.getMetadataValue(meta_list, "does_paging");
118 if (value.equals("true")) {
119 does_paging = true;
120 }
121 }
122
123 if (does_paging == false) {
124 // we will do the paging, so lets add in a hitsPerPage param to the service
125 addHitsParamToService(doc, service_description, lang);
126 }
127 }
128 //Element service_description = (Element) doc.importNode(GSXML.getChildByTagName(service_response, GSXML.SERVICE_ELEM), true);
129
130
131 // have we been asked to return the service description
132 // as part of the response?
133 if (request_type.indexOf("d") != -1) {
134 if (service_description != null) {
135 page_response.appendChild(service_description);
136 }
137 addCollectionsHierarchy(page_response,userContext);
138 }
139
140 if (request_type.indexOf("r") == -1)
141 {
142 // just a display request, no actual processing to do
143 //append site metadata
144 addSiteMetadata(page_response, userContext);
145 addInterfaceOptions(page_response);
146 return page_response;
147 }
148
149 // check that we have some service params
150 HashMap service_params = (HashMap) params.get("s1");
151 if (service_params == null)
152 { // no query
153 //append site metadata
154 addSiteMetadata(page_response, userContext);
155 addInterfaceOptions(page_response);
156 return page_response;
157 }
158
159 // create the query request
160 Element mr_query_message = doc.createElement(GSXML.MESSAGE_ELEM);
161 Element mr_query_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
162 mr_query_message.appendChild(mr_query_request);
163
164 Element query_param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
165 GSXML.addParametersToList(query_param_list, service_params);
166 mr_query_request.appendChild(query_param_list);
167
168 // do the query
169 Element mr_query_response = (Element) this.mr.process(mr_query_message);
170
171 // check for errors
172 if (processErrorElements(mr_query_response, page_response))
173 {
174 //append site metadata
175 addSiteMetadata(page_response, userContext);
176 addInterfaceOptions(page_response);
177 return page_response;
178 }
179
180 Element query_response = (Element) GSXML.getChildByTagName(mr_query_response, GSXML.RESPONSE_ELEM);
181 Element query_result_metadata_list = (Element) GSXML.getChildByTagName(query_response, GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
182
183 if (query_result_metadata_list == null)
184 {
185 logger.error("No query result metadata.\n");
186 }
187 else
188 { // add it into the page response
189 page_response.appendChild(doc.importNode(query_result_metadata_list, true));
190 }
191
192 Element query_term_info_list = (Element) GSXML.getChildByTagName(query_response, GSXML.TERM_ELEM + GSXML.LIST_MODIFIER);
193 if (query_term_info_list == null)
194 {
195 logger.error("No query term information.\n");
196 }
197 else
198 { // add it into the page response
199 page_response.appendChild(doc.importNode(query_term_info_list, true));
200 }
201
202 Element facet_list = (Element) GSXML.getChildByTagName(query_response, GSXML.FACET_ELEM + GSXML.LIST_MODIFIER);
203 if (facet_list == null)
204 {
205 logger.error("No query term information.\n");
206 }
207 else
208 { // add it into the page response
209 page_response.appendChild(doc.importNode(facet_list, true));
210 }
211
212 // check that there are some documents - for now check the list, but later should use a numdocs metadata elem
213 Element document_list = (Element) GSXML.getChildByTagName(query_response, GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
214 // documentList not present if no docs found
215 if (document_list == null)
216 {
217 // add in a dummy doc node list - used by the display. need to think about this
218 page_response.appendChild(doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER));
219 //append site metadata
220 addSiteMetadata(page_response, userContext);
221 addInterfaceOptions(page_response);
222 return page_response;
223 }
224
225 // now we check to see if there is metadata already - some search services return predefined metadata. if there is some, don't do a metadata request
226 NodeList doc_metadata = document_list.getElementsByTagName(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
227 if (doc_metadata.getLength() > 0)
228 {
229 // why are we not paging these results?????
230 // append the doc list to the result
231 page_response.appendChild(doc.importNode(document_list, true));
232 //append site metadata
233 addSiteMetadata(page_response, userContext);
234 addInterfaceOptions(page_response);
235 return page_response;
236 }
237
238 // get the metadata elements needed from the format statement if any
239 HashSet<String> metadata_names = new HashSet<String>();
240 metadata_names.add("Title");
241 // we already got the format element earlier
242 if (format_elem != null)
243 {
244 getRequiredMetadataNames(format_elem, metadata_names);
245 }
246
247 // paging of the results is done here - we filter the list to remove unwanted entries before retrieving metadata
248 Element filtered_doc_list;
249 if (does_paging) {
250 filtered_doc_list = (Element)doc.importNode(document_list, true);
251 } else {
252 filtered_doc_list = filterDocList(doc, params, service_params, document_list);
253 }
254 // do the metadata request on the filtered list
255 Element mr_metadata_message = doc.createElement(GSXML.MESSAGE_ELEM);
256 to = "DocumentMetadataRetrieve";
257 if (collection != null)
258 {
259 to = GSPath.prependLink(to, collection);
260 }
261 Element mr_metadata_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
262 mr_metadata_message.appendChild(mr_metadata_request);
263
264 // just get all for now - the receptionist should perhaps pass in some
265 // metadata that it wants, and QueryAction should look through the format stuff to see if there is any other?
266
267 Element extraMetaListElem = (Element) GSXML.getChildByTagName(request, GSXML.EXTRA_METADATA + GSXML.LIST_MODIFIER);
268 if(extraMetaListElem != null)
269 {
270 NodeList extraMetaList = extraMetaListElem.getElementsByTagName(GSXML.EXTRA_METADATA);
271 for(int i = 0; i < extraMetaList.getLength(); i++)
272 {
273 metadata_names.add(((Element)extraMetaList.item(i)).getAttribute(GSXML.NAME_ATT));
274 }
275 }
276
277 Element dm_param_list = createMetadataParamList(doc,metadata_names);
278
279 mr_metadata_request.appendChild(dm_param_list);
280
281 // add in the doc node list too
282 mr_metadata_request.appendChild(filtered_doc_list);
283
284 Element mr_metadata_response = (Element) this.mr.process(mr_metadata_message);
285
286 Element query_result_snippet_list = (Element) GSXML.getChildByTagName(query_response, GSXML.HL_SNIPPET_ELEM + GSXML.LIST_MODIFIER);
287
288 // check for errors
289 processErrorElements(mr_metadata_response, page_response);
290
291 Element metadata_response = (Element) GSXML.getChildByTagName(mr_metadata_response, GSXML.RESPONSE_ELEM);
292
293 Element query_result_document_list = (Element) GSXML.getChildByTagName(metadata_response, GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
294
295 if (query_result_document_list != null)
296 {
297 page_response.appendChild(doc.importNode(query_result_document_list, true));
298 if (query_result_snippet_list != null)
299 {
300 page_response.appendChild(doc.importNode(query_result_snippet_list,true));
301 }
302 }
303
304 //logger.debug("Query page:\n" + this.converter.getPrettyString(page_response));
305 //append site metadata
306 addSiteMetadata(page_response, userContext);
307 addInterfaceOptions(page_response);
308 return page_response;
309 }
310
311 private void addCollectionsHierarchy(Element page_response, UserContext userContext) {
312 Document doc = page_response.getOwnerDocument();
313 String collectionsHierarchy = "CollectionsHierarchy";
314 if (checkServiceAvailable(userContext, collectionsHierarchy)){
315 Element groupQueryMessage = doc.createElement(GSXML.MESSAGE_ELEM);
316 Element groupQueryRequest = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, collectionsHierarchy, userContext);
317 groupQueryMessage.appendChild(groupQueryRequest);
318 Element groupQueryResult = (Element) this.mr.process(groupQueryMessage);
319 if (groupQueryResult == null){
320 return;
321 }
322 Element groupQueryResponse = (Element) GSXML.getChildByTagName(groupQueryResult, GSXML.RESPONSE_ELEM);
323 if (groupQueryResponse == null){
324 return;
325 }
326 Element hierarchy = (Element) GSXML.getChildByTagName(groupQueryResponse, GSXML.HIERARCHY_ELEM);
327 page_response.appendChild(doc.importNode(hierarchy, true));
328 }
329
330
331 }
332
333 private boolean checkServiceAvailable(UserContext userContext, String collectionsHierarchy) {
334
335 Document doc = XMLConverter.newDOM();
336 Element infoMessage = doc.createElement(GSXML.MESSAGE_ELEM);
337 Element infoRequest = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, "", userContext);
338 Element paramList = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
339 infoRequest.appendChild(paramList);
340 GSXML.addParameterToList(paramList, GSXML.SUBSET_PARAM, GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
341 infoMessage.appendChild(infoRequest);
342 Element responseMessage = (Element) this.mr.process(infoMessage);
343 if (responseMessage == null)
344 {
345 logger.error("couldn't query the message router!");
346 return false;
347 }
348 NodeList serviceLists = responseMessage.getElementsByTagName(GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
349 if (serviceLists == null || serviceLists.getLength() == 0){
350 logger.error("No service List in response message from message router!");
351 return false;
352 }
353 Element serviceList = (Element) serviceLists.item(0);
354 Element groupInfoService = GSXML.getNamedElement(serviceList, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, collectionsHierarchy);
355 if (groupInfoService == null){
356 logger.error("service " + collectionsHierarchy + " unavailable");
357 return false;
358 }
359 return true;
360 }
361
362 /** this filters out some of the doc results for result paging */
363 protected Element filterDocList(Document doc, HashMap<String, Serializable> params, HashMap service_params, Element orig_doc_list)
364 {
365
366 String hits_pp = (String) service_params.get(HITS_PER_PAGE_ARG);
367
368 int hits = 20;
369 if (hits_pp != null && !hits_pp.equals(""))
370 {
371 if (hits_pp.equals("all")) {
372 hits = -1;
373 } else {
374 try
375 {
376 hits = Integer.parseInt(hits_pp);
377 }
378 catch (Exception e)
379 {
380 hits = 20;
381 }
382 }
383 }
384 if (hits == -1)
385 { // all
386 return (Element) doc.importNode(orig_doc_list, true);
387 }
388 NodeList result_docs = orig_doc_list.getElementsByTagName(GSXML.DOC_NODE_ELEM);
389
390 int num_docs = result_docs.getLength();
391 if (num_docs <= hits)
392 {
393 // too few docs to do paging
394 return (Element) doc.importNode(orig_doc_list, true);
395 }
396
397 // now we need our own doc list
398 Element result_list = doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
399
400 String start_p = (String) service_params.get("startPage");
401 if (start_p == null)
402 {
403 start_p = (String) params.get("startPage");
404 }
405
406 int start = 1;
407 if (start_p != null && !start_p.equals(""))
408 {
409 try
410 {
411 start = Integer.parseInt(start_p);
412 }
413 catch (Exception e)
414 {
415 start = 1;
416 }
417 }
418 int start_from = (start - 1) * hits;
419 int end_at = (start * hits) - 1;
420
421 if (start_from > num_docs)
422 {
423 // something has gone wrong
424 return result_list;
425 }
426
427 if (end_at > num_docs)
428 {
429 end_at = num_docs - 1;
430 }
431 // now we finally have the docs numbers to use
432 for (int i = start_from; i <= end_at; i++)
433 {
434 result_list.appendChild(doc.importNode(result_docs.item(i), true));
435 }
436
437 return result_list;
438 }
439
440 protected boolean addHitsParamToService(Document doc, Element service_description, String lang) {
441 Element param_list = (Element)GSXML.getChildByTagName(service_description, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
442 Element param = GSXML.createParameterDescription(doc, HITS_PER_PAGE_ARG, getTextString("param." + HITS_PER_PAGE_ARG, lang, "ServiceRack", null), GSXML.PARAM_TYPE_INTEGER, "20", null, null);
443 Element query_param = GSXML.getNamedElement(param_list, GSXML.PARAM_ELEM, GSXML.NAME_ATT, "query");
444 if (query_param != null) {
445 param_list.insertBefore(param, query_param);
446 } else {
447 param_list.appendChild(param);
448 }
449 return true;
450 }
451
452}
Note: See TracBrowser for help on using the repository browser.