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

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

Analyse xsl files in advance to find out what metadata we need

  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 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 extraMetaListElem = (Element) GSXML.getChildByTagName(request, GSXML.EXTRA_METADATA + GSXML.LIST_MODIFIER);
231 if(extraMetaListElem != null)
232 {
233 NodeList extraMetaList = extraMetaListElem.getElementsByTagName(GSXML.EXTRA_METADATA);
234 for(int i = 0; i < extraMetaList.getLength(); i++)
235 {
236 metadata_names.add(((Element)extraMetaList.item(i)).getAttribute(GSXML.NAME_ATT));
237 }
238 }
239
240 Element dm_param_list = createMetadataParamList(metadata_names);
241
242 mr_metadata_request.appendChild(dm_param_list);
243
244 // add in the doc node list too
245 mr_metadata_request.appendChild(filtered_doc_list);
246
247 Element mr_metadata_response = (Element) this.mr.process(mr_metadata_message);
248
249 // check for errors
250 processErrorElements(mr_metadata_response, page_response);
251
252 Element metadata_response = (Element) GSXML.getChildByTagName(mr_metadata_response, GSXML.RESPONSE_ELEM);
253
254 Element query_result_document_list = (Element) GSXML.getChildByTagName(metadata_response, GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
255
256 if (query_result_document_list != null)
257 {
258 page_response.appendChild(this.doc.importNode(query_result_document_list, true));
259 }
260
261 logger.debug("Query page:\n" + this.converter.getPrettyString(page_response));
262 //append site metadata
263 addSiteMetadata(page_response, userContext);
264 addInterfaceOptions(page_response);
265 return page_response;
266 }
267
268 /** this filters out some of the doc results for result paging */
269 protected Element filterDocList(HashMap<String, Serializable> params, HashMap service_params, Element orig_doc_list)
270 {
271
272 // check the hits_per_page param - is it a service param??
273 String hits_pp = (String) service_params.get("hitsPerPage");
274 if (hits_pp == null)
275 {
276 // the service is doing the paging, so we want to display all of the returned docs(???)
277 // return (Element)this.doc.importNode(orig_doc_list, true);
278 // try hitsPerPage in the globle param
279 hits_pp = (String) params.get("hitsPerPage");
280 }
281
282 int hits = 20;
283 if (hits_pp != null && !hits_pp.equals(""))
284 {
285 try
286 {
287 hits = Integer.parseInt(hits_pp);
288 }
289 catch (Exception e)
290 {
291 hits = 20;
292 }
293 }
294
295 if (hits == -1)
296 { // all
297 return (Element) this.doc.importNode(orig_doc_list, true);
298 }
299 NodeList result_docs = orig_doc_list.getElementsByTagName(GSXML.DOC_NODE_ELEM);
300
301 int num_docs = result_docs.getLength();
302 if (num_docs <= hits)
303 {
304 // too few docs to do paging
305 return (Element) this.doc.importNode(orig_doc_list, true);
306 }
307
308 // now we need our own doc list
309 Element result_list = this.doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
310
311 String start_p = (String) service_params.get("startPage");
312 if (start_p == null)
313 {
314 start_p = (String) params.get("startPage");
315 }
316
317 int start = 1;
318 if (start_p != null && !start_p.equals(""))
319 {
320 try
321 {
322 start = Integer.parseInt(start_p);
323 }
324 catch (Exception e)
325 {
326 start = 1;
327 }
328 }
329
330 int start_from = (start - 1) * hits;
331 int end_at = (start * hits) - 1;
332
333 if (start_from > num_docs)
334 {
335 // something has gone wrong
336 return result_list;
337 }
338
339 if (end_at > num_docs)
340 {
341 end_at = num_docs - 1;
342 }
343
344 // now we finally have the docs numbers to use
345 for (int i = start_from; i <= end_at; i++)
346 {
347 result_list.appendChild(this.doc.importNode(result_docs.item(i), true));
348 }
349
350 return result_list;
351 }
352
353}
Note: See TracBrowser for help on using the repository browser.