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

Last change on this file since 25986 was 25986, checked in by sjm84, 12 years ago

All of the actions that use format statements will now merge in the global format statement

  • Property svn:keywords set to Author Date Id Revision
File size: 11.4 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 if (request_type.indexOf("d") != -1)
73 {
74 // we have been asked for the service description
75 Element mr_info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
76 Element mr_info_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, to, userContext);
77 mr_info_message.appendChild(mr_info_request);
78
79 // process the message
80 Element mr_info_response = (Element) this.mr.process(mr_info_message);
81 // the response
82
83 Element service_response = (Element) GSXML.getChildByTagName(mr_info_response, GSXML.RESPONSE_ELEM);
84
85 Element service_description = (Element) this.doc.importNode(GSXML.getChildByTagName(service_response, GSXML.SERVICE_ELEM), true);
86 page_response.appendChild(service_description);
87 }
88
89 if (request_type.indexOf("r") == -1)
90 {
91 // just a display request, no actual processing to do
92 //append site metadata
93 addSiteMetadata(page_response, userContext);
94 addInterfaceOptions(page_response);
95 return page_response;
96 }
97
98 // check that we have some service params
99 HashMap service_params = (HashMap) params.get("s1");
100 if (service_params == null)
101 { // no query
102 //append site metadata
103 addSiteMetadata(page_response, userContext);
104 addInterfaceOptions(page_response);
105 return page_response;
106 }
107
108 // create the query request
109 Element mr_query_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
110 Element mr_query_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
111 mr_query_message.appendChild(mr_query_request);
112
113 Element query_param_list = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
114 GSXML.addParametersToList(this.doc, query_param_list, service_params);
115 mr_query_request.appendChild(query_param_list);
116
117 // also get the format stuff now if there is some
118 Element format_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_FORMAT, to, userContext);
119 mr_query_message.appendChild(format_request);
120
121 logger.debug(GSXML.xmlNodeToString(mr_query_message));
122
123 // do the query
124 Element mr_query_response = (Element) this.mr.process(mr_query_message);
125
126 // check for errors
127 if (processErrorElements(mr_query_response, page_response))
128 {
129 //append site metadata
130 addSiteMetadata(page_response, userContext);
131 addInterfaceOptions(page_response);
132 return page_response;
133 }
134
135 NodeList responses = mr_query_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
136 Element query_response = (Element) responses.item(0);
137 Element format_response = (Element) responses.item(1);
138
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 // add in the format info to the stylesheet if there is any
199 Element format_elem = (Element) GSXML.getChildByTagName(format_response, GSXML.FORMAT_ELEM);
200 if (format_elem != null)
201 {
202 Element global_format_elem = (Element) GSXML.getChildByTagName(format_response, GSXML.GLOBAL_FORMAT_ELEM);
203 if (global_format_elem != null)
204 {
205 GSXSLT.mergeFormatElements(format_elem, global_format_elem, false);
206 }
207 // set the format type
208 format_elem.setAttribute(GSXML.TYPE_ATT, "search");
209 // for now just add to the response
210 page_response.appendChild(this.doc.importNode(format_elem, true));
211 getRequiredMetadataNames(format_elem, metadata_names);
212 }
213
214 // paging of the results is done here - we filter the list to remove unwanted entries before retrieving metadata
215 Element filtered_doc_list = filterDocList(params, service_params, document_list);
216
217 // do the metadata request on the filtered list
218 Element mr_metadata_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
219 to = "DocumentMetadataRetrieve";
220 if (collection != null)
221 {
222 to = GSPath.prependLink(to, collection);
223 }
224 Element mr_metadata_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
225 mr_metadata_message.appendChild(mr_metadata_request);
226
227 // just get all for now - the receptionist should perhaps pass in some
228 // metadata that it wants, and QueryAction should look through the format stuff to see if there is any other?
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.