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

Last change on this file since 31285 was 31285, checked in by Georgiy Litvinov, 7 years ago

Java code for hierarchy view in cross collection search

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