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

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

xmlNodeToString will always print text now

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