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

Last change on this file since 27145 was 27145, checked in by kjdon, 11 years ago

get the format info even when we are just displaying the search page. This means that we will get any global format info, including for example additionalHeaderContent template which may link to a different theme just for the collection

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