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

Last change on this file since 30094 was 30094, checked in by Georgiy Litvinov, 9 years ago

Check for existence of snippets

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