source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractGS2FieldSearch.java@ 28966

Last change on this file since 28966 was 28966, checked in by kjdon, 10 years ago

Lots of changes. Mainly to do with removing this.doc from everywhere. Document is not thread safe. Now we tend to create a new Document everytime we are starting a new page/message etc. in service this.desc_doc is available as teh document to create service info stuff. But it should only be used for this and not for other messages. newDOM is now static for XMLConverter. method param changes for some GSXML methods.

  • Property svn:keywords set to Author Date Id Revision
File size: 29.0 KB
Line 
1/*
2 * AbstractGS2FieldSearch.java
3 * Copyright (C) 2006 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18package org.greenstone.gsdl3.service;
19
20// Greenstone classes
21import java.io.Serializable;
22import java.util.ArrayList;
23import java.util.HashMap;
24
25import org.apache.log4j.Logger;
26import org.greenstone.gsdl3.util.FacetWrapper;
27import org.greenstone.gsdl3.util.GSXML;
28import org.greenstone.gsdl3.util.XMLConverter;
29
30import org.w3c.dom.Document;
31import org.w3c.dom.Element;
32import org.w3c.dom.NodeList;
33
34abstract public class AbstractGS2FieldSearch extends AbstractGS2TextSearch
35{
36 // extra services offered by mgpp collections
37 protected static final String FIELD_QUERY_SERVICE = "FieldQuery";
38 protected static final String ADVANCED_FIELD_QUERY_SERVICE = "AdvancedFieldQuery";
39 protected static final String RAW_QUERY_SERVICE = "RawQuery";
40
41 // extra parameters used
42 protected static final String LEVEL_PARAM = "level";
43 protected static final String RANK_PARAM = "sortBy";
44 protected static final String RANK_PARAM_RANK = "1";
45 protected static final String RANK_PARAM_NONE = "0";
46 protected static final String SIMPLE_FIELD_PARAM = "simpleField";
47 protected static final String ADVANCED_FIELD_PARAM = "complexField";
48
49 protected static final String RAW_PARAM = "rawquery";
50
51 // more params for field query
52 protected static final String FIELD_QUERY_PARAM = "fqv";
53 protected static final String FIELD_STEM_PARAM = "fqs";
54 protected static final String FIELD_CASE_PARAM = "fqc";
55 protected static final String FIELD_ACCENT_PARAM = "fqa";
56 protected static final String FIELD_FIELD_PARAM = "fqf";
57 protected static final String FIELD_COMBINE_PARAM = "fqk";
58 protected static final String FIELD_COMBINE_PARAM_AND = "0";
59 protected static final String FIELD_COMBINE_PARAM_OR = "1";
60 protected static final String FIELD_COMBINE_PARAM_NOT = "2";
61
62 // some stuff for config files
63 protected static final String SEARCH_TYPE_ELEM = "searchType";
64 protected static final String SEARCH_TYPE_PLAIN = "plain";
65 protected static final String SEARCH_TYPE_SIMPLE_FORM = "simpleform";
66 protected static final String SEARCH_TYPE_ADVANCED_FORM = "advancedform";
67 protected static final String SEARCH_TYPE_RAW = "raw";
68
69 protected static final String DEFAULT_LEVEL_ELEM = "defaultLevel";
70 protected static final String DEFAULT_DB_LEVEL_ELEM = "defaultDBLevel";
71 protected static final String LEVEL_ELEM = "level";
72 protected static final String FIELD_ATT = "field";
73
74 protected static final int TEXT_QUERY = 0;
75 protected static final int SIMPLE_QUERY = 1;
76 protected static final int ADVANCED_QUERY = 2;
77 protected static final int RAW_QUERY = 3;
78
79 protected String AND_OPERATOR = "&";
80 protected String OR_OPERATOR = "|";
81 protected String NOT_OPERATOR = "!";
82
83 // the default level for searching
84 protected String default_level = null;
85 // default level for collection db
86 protected String default_db_level = null;
87 // which search services will we offer??
88 protected boolean plain_search = false;
89 protected boolean simple_form_search = false;
90 protected boolean advanced_form_search = false;
91 protected boolean raw_search = false;
92
93 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractGS2FieldSearch.class.getName());
94
95 /** constructor */
96 public AbstractGS2FieldSearch()
97 {
98 super();
99 paramDefaults.put(RANK_PARAM, RANK_PARAM_RANK);
100 paramDefaults.put(FIELD_COMBINE_PARAM, FIELD_COMBINE_PARAM_AND);
101 // paramDefaults.put(FIELD_CASE_PARAM, BOOLEAN_PARAM_ON);
102 // paramDefaults.put(FIELD_STEM_PARAM, BOOLEAN_PARAM_OFF);
103 // paramDefaults.put(FIELD_ACCENT_PARAM, BOOLEAN_PARAM_ON);
104 }
105
106 public void cleanUp()
107 {
108 super.cleanUp();
109 }
110
111 /** configure this service */
112 public boolean configure(Element info, Element extra_info)
113 {
114 if (!super.configure(info, extra_info))
115 {
116 return false;
117 }
118
119 // Get the default level out of <defaultLevel> (buildConfig.xml)
120 Element def = (Element) GSXML.getChildByTagName(info, DEFAULT_LEVEL_ELEM);
121 if (def != null)
122 {
123 this.default_level = def.getAttribute(GSXML.SHORTNAME_ATT);
124 }
125 if (this.default_level == null || this.default_level.equals(""))
126 {
127 logger.error("default level not specified!, assuming Doc");
128 this.default_level = "Doc";
129 }
130
131 // Get the default DB level
132 def = (Element) GSXML.getChildByTagName(info, DEFAULT_DB_LEVEL_ELEM);
133 if (def != null)
134 {
135 this.default_db_level = def.getAttribute(GSXML.SHORTNAME_ATT);
136 }
137 if (this.default_db_level == null || this.default_db_level.equals(""))
138 {
139 logger.error("default database level (defaultDBLevel) not specified!, assuming Sec");
140 this.default_db_level = "Sec";
141 }
142
143 // get stuff from from extra info (which is collectionConfig.xml)
144 if (extra_info != null)
145 {
146
147 // the search element
148 Element config_search = (Element) GSXML.getChildByTagName(extra_info, GSXML.SEARCH_ELEM);
149
150 NodeList search_types = config_search.getElementsByTagName(SEARCH_TYPE_ELEM);
151 if (search_types == null)
152 {
153 // none specified, assume plain only
154 this.plain_search = true;
155 }
156 else
157 {
158 for (int i = 0; i < search_types.getLength(); i++)
159 {
160 Element t = (Element) search_types.item(i);
161
162 String type_name = t.getAttribute(GSXML.NAME_ATT);
163 if (type_name.equals(SEARCH_TYPE_PLAIN))
164 {
165 this.plain_search = true;
166 }
167 else if (type_name.equals(SEARCH_TYPE_SIMPLE_FORM))
168 {
169 this.simple_form_search = true;
170 }
171 else if (type_name.equals(SEARCH_TYPE_ADVANCED_FORM))
172 {
173 this.advanced_form_search = true;
174 }
175 else if (type_name.equals(SEARCH_TYPE_RAW))
176 {
177 this.raw_search = true;
178 }
179 }
180 }
181
182 // AbstractGS2TextSearch has set up the TextQuery service, but we may not want it
183 if (!this.plain_search)
184 {
185 // need to remove the TextQuery service
186 Element tq_service = GSXML.getNamedElement(short_service_info, GSXML.SERVICE_ELEM, GSXML.NAME_ATT, QUERY_SERVICE);
187 short_service_info.removeChild(tq_service);
188 }
189
190 Document owner = info.getOwnerDocument();
191
192 NodeList levels = info.getElementsByTagName(GSXML.LEVEL_ELEM);
193
194 for (int i = 0; i < levels.getLength(); i++)
195 {
196 Element lev = (Element) levels.item(i);
197 String name = lev.getAttribute(GSXML.NAME_ATT);
198 Element node_extra = GSXML.getNamedElement(config_search, GSXML.LEVEL_ELEM, GSXML.NAME_ATT, name);
199 if (node_extra == null)
200 {
201 logger.error("haven't found extra info for level named " + name);
202 continue;
203 }
204
205 // get the display elements if any - displayName
206 NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
207 if (display_names != null)
208 {
209 for (int j = 0; j < display_names.getLength(); j++)
210 {
211 Element e = (Element) display_names.item(j);
212 lev.appendChild(owner.importNode(e, true));
213 }
214 }
215 } // for each level
216 }
217 else
218 {
219 // for soem reason we don't have the collectionConfig file. assume plain only
220 this.plain_search = true;
221 }
222
223 // the format info is the same for all services
224 Element format_info = (Element) format_info_map.get(QUERY_SERVICE);
225
226 // set up the extra services which are available for this collection
227 if (this.simple_form_search)
228 {
229 // set up short_service_info_ - for now just has id and type - name will be added in on the fly
230 Element fq_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
231 fq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
232 fq_service.setAttribute(GSXML.NAME_ATT, FIELD_QUERY_SERVICE);
233 this.short_service_info.appendChild(fq_service);
234
235 if (format_info != null)
236 {
237 this.format_info_map.put(FIELD_QUERY_SERVICE, format_info);
238 }
239 }
240
241 if (this.advanced_form_search)
242 {
243 Element afq_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
244 afq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
245 afq_service.setAttribute(GSXML.NAME_ATT, ADVANCED_FIELD_QUERY_SERVICE);
246 this.short_service_info.appendChild(afq_service);
247
248 if (format_info != null)
249 {
250 this.format_info_map.put(ADVANCED_FIELD_QUERY_SERVICE, format_info);
251 }
252 }
253
254 if (this.raw_search)
255 {
256 Element rq_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
257 rq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
258 rq_service.setAttribute(GSXML.NAME_ATT, RAW_QUERY_SERVICE);
259 this.short_service_info.appendChild(rq_service);
260
261 if (format_info != null)
262 {
263 this.format_info_map.put(RAW_QUERY_SERVICE, format_info);
264 }
265 }
266
267 return true;
268 }
269
270 // if field case/stem/accent defaults are not specified explicitly, we should use case/stem/accent defaults
271 protected void getSearchParamDefaults(Element search_elem) {
272
273 boolean found_f_stem = false;
274 boolean found_f_case = false;
275 boolean found_f_accent = false;
276 NodeList param_defaults_list = GSXML.getChildrenByTagName(search_elem, GSXML.PARAM_DEFAULT_ELEM);
277 for (int i=0; i<param_defaults_list.getLength(); i++) {
278 Element paramdef = (Element)param_defaults_list.item(i);
279 String name = paramdef.getAttribute(GSXML.NAME_ATT);
280 String val = paramdef.getAttribute(GSXML.VALUE_ATT);
281 if (!name.equals("") && !val.equals("")) {
282 paramDefaults.put(name, val);
283 if (name.equals(FIELD_STEM_PARAM)) {
284 found_f_stem = true;
285 } else if (name.equals(FIELD_CASE_PARAM)) {
286 found_f_case = true;
287 } else if (name.equals(FIELD_ACCENT_PARAM)) {
288 found_f_accent = true;
289 }
290 if (!found_f_stem) {
291 paramDefaults.put (FIELD_STEM_PARAM, paramDefaults.get(STEM_PARAM));
292 }
293 if (!found_f_case) {
294 paramDefaults.put (FIELD_CASE_PARAM, paramDefaults.get(CASE_PARAM));
295 }
296 if (!found_f_accent) {
297 paramDefaults.put (FIELD_ACCENT_PARAM, paramDefaults.get(ACCENT_PARAM));
298 }
299
300 }
301 }
302 }
303 protected Element getServiceDescription(Document doc, String service_id, String lang, String subset)
304 {
305 // should we check that the service is actually on offer? presumably we wont get asked for services that we haven't advertised previously.
306
307 if (!service_id.equals(FIELD_QUERY_SERVICE) && !service_id.equals(ADVANCED_FIELD_QUERY_SERVICE) && !service_id.equals(RAW_QUERY_SERVICE))
308 {
309 return super.getServiceDescription(doc, service_id, lang, subset);
310 }
311
312 Element service = doc.createElement(GSXML.SERVICE_ELEM);
313 service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
314 service.setAttribute(GSXML.NAME_ATT, service_id);
315 if (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER))
316 {
317 service.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_NAME, getTextString(service_id + ".name", lang)));
318 service.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_SUBMIT, getTextString(service_id + ".submit", lang)));
319 service.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(service_id + ".description", lang)));
320
321 }
322 if (subset == null || subset.equals(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER))
323 {
324 Element param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
325 service.appendChild(param_list);
326 if (service_id.equals(FIELD_QUERY_SERVICE))
327 {
328
329 addCustomQueryParams(param_list, lang);
330 createParameter(MAXDOCS_PARAM, param_list, lang);
331 if (!default_index_subcollection.equals(""))
332 {
333 createParameter(INDEX_SUBCOLLECTION_PARAM, param_list, lang);
334 }
335 if (!default_index_language.equals(""))
336 {
337 createParameter(INDEX_LANGUAGE_PARAM, param_list, lang);
338 }
339
340 if (does_paging)
341 {
342 createParameter(HITS_PER_PAGE_PARAM, param_list, lang);
343 createParameter(START_PAGE_PARAM, param_list, lang);
344 }
345
346 // create a multi param for the fields etc
347 // text box, field
348 Element multiparam = null;
349 Element param = null;
350 multiparam = GSXML.createParameterDescription(doc, SIMPLE_FIELD_PARAM, "", GSXML.PARAM_TYPE_MULTI, null, null, null);
351 multiparam.setAttribute("occurs", "4");
352 param_list.appendChild(multiparam);
353
354 // the components
355
356 createParameter(FIELD_QUERY_PARAM, multiparam, lang);
357 createParameter(FIELD_FIELD_PARAM, multiparam, lang);
358
359 }
360 else if (service_id.equals(ADVANCED_FIELD_QUERY_SERVICE))
361 {
362 createParameter(LEVEL_PARAM, param_list, lang);
363 createParameter(RANK_PARAM, param_list, lang);
364 createParameter(MAXDOCS_PARAM, param_list, lang);
365 if (!default_index_subcollection.equals(""))
366 {
367 createParameter(INDEX_SUBCOLLECTION_PARAM, param_list, lang);
368 }
369 if (!default_index_language.equals(""))
370 {
371 createParameter(INDEX_LANGUAGE_PARAM, param_list, lang);
372 }
373
374 // create a multi param for the fields etc
375 // text box, stem, case, field
376
377 Element multiparam = null;
378 Element param = null;
379
380 multiparam = GSXML.createParameterDescription(doc, ADVANCED_FIELD_PARAM, "", GSXML.PARAM_TYPE_MULTI, null, null, null);
381 multiparam.setAttribute("occurs", "4");
382 param_list.appendChild(multiparam);
383
384 createParameter(FIELD_COMBINE_PARAM, multiparam, lang);
385 createParameter(FIELD_QUERY_PARAM, multiparam, lang);
386 if (this.does_case)
387 {
388 createParameter(FIELD_CASE_PARAM, multiparam, lang);
389 }
390 if (this.does_stem)
391 {
392 createParameter(FIELD_STEM_PARAM, multiparam, lang);
393 }
394 if (this.does_accent)
395 {
396 createParameter(FIELD_ACCENT_PARAM, multiparam, lang);
397 }
398 if (does_paging)
399 {
400 createParameter(HITS_PER_PAGE_PARAM, param_list, lang);
401 createParameter(START_PAGE_PARAM, param_list, lang);
402 }
403 createParameter(FIELD_FIELD_PARAM, multiparam, lang);
404
405 }
406 else if (service_id.equals(RAW_QUERY_SERVICE))
407 {
408 if (does_chunking)
409 {
410 createParameter(MAXDOCS_PARAM, param_list, lang);
411 }
412 if (does_paging)
413 {
414 createParameter(HITS_PER_PAGE_PARAM, param_list, lang);
415 createParameter(START_PAGE_PARAM, param_list, lang);
416 }
417 createParameter(RAW_PARAM, param_list, lang);
418 service.appendChild(param_list);
419 }
420 }
421 return service;
422
423 }
424
425 /** add in the level params to TextQuery */
426 protected void addCustomQueryParams(Element param_list, String lang)
427 {
428 createParameter(LEVEL_PARAM, param_list, lang);
429 super.addCustomQueryParams(param_list, lang);
430 }
431
432 /** create a param and add to the list */
433 protected void createParameter(String name, Element param_list, String lang)
434 {
435 Document doc = param_list.getOwnerDocument();
436 Element param = null;
437 String param_default = paramDefaults.get(name);
438 if (name.equals(LEVEL_PARAM))
439 {
440 ArrayList<String> level_ids = new ArrayList<String>();
441 ArrayList<String> level_names = new ArrayList<String>();
442 getLevelData(level_ids, level_names, lang);
443 if (level_ids.size() > 1)
444 {
445 // the first one is the default
446 //param = GSXML.createParameterDescription2(doc, LEVEL_PARAM, getTextString("param."+LEVEL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)level_ids.get(0), level_ids, level_names);
447 param = GSXML.createParameterDescription2(doc, LEVEL_PARAM, getTextString("param." + LEVEL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, this.default_level, level_ids, level_names);
448 }
449 else
450 {
451 // we need to set the level, but hidden, in case there is an invalid level saved
452 //param = GSXML.createParameterDescription(doc, LEVEL_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, (String)level_ids.get(0), null, null);
453 param = GSXML.createParameterDescription(doc, LEVEL_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, this.default_level, null, null);
454 }
455 }
456 else if (name.equals(RANK_PARAM))
457 {
458 String[] vals1 = { RANK_PARAM_RANK, RANK_PARAM_NONE };
459 String[] vals1_texts = { getTextString("param." + RANK_PARAM + "." + RANK_PARAM_RANK, lang), getTextString("param." + RANK_PARAM + "." + RANK_PARAM_NONE, lang) };
460
461 param = GSXML.createParameterDescription(doc, RANK_PARAM, getTextString("param." + RANK_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, param_default, vals1, vals1_texts);
462
463 }
464 else if (name.equals(FIELD_QUERY_PARAM))
465 {
466 param = GSXML.createParameterDescription(doc, FIELD_QUERY_PARAM, getTextString("param." + FIELD_QUERY_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
467
468 }
469 else if (name.equals(FIELD_CASE_PARAM) || name.equals(FIELD_STEM_PARAM) || name.equals(FIELD_ACCENT_PARAM))
470 {
471 String[] bool_ops = { "0", "1" };
472 String[] bool_texts = { getTextString("param.boolean.off", lang, "AbstractTextSearch"), getTextString("param.boolean.on", lang, "AbstractTextSearch") };
473 param = GSXML.createParameterDescription(doc, name, getTextString("param." + name, lang), GSXML.PARAM_TYPE_BOOLEAN, param_default, bool_ops, bool_texts);
474
475 }
476 else if (name.equals(FIELD_FIELD_PARAM))
477 {
478 ArrayList<String> fields = new ArrayList<String>();
479 ArrayList<String> field_names = new ArrayList<String>();
480 getIndexData(fields, field_names, lang);
481 // the field list - read from config file
482
483 // Fix for http://trac.greenstone.org/ticket/245 "java crash, index out of bounds"
484 // org.greenstone.gsdl3.service.AbstractGS2FieldSearch.createParameter(AbstractGS2FieldSearch.java:362)
485 // Changed from:
486 // param = GSXML.createParameterDescription2(doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)fields.get(0), fields, field_names );
487 String default_value = (fields.size() > 0) ? fields.get(0) : null;
488 // don't want to access element 0 if fields.size()==0, and
489 // GSXML.createParameterDescription2 checks for default_value==null condition
490 param = GSXML.createParameterDescription2(doc, name, getTextString("param." + name, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, default_value, fields, field_names);
491
492 }
493 else if (name.equals(FIELD_COMBINE_PARAM))
494 {
495
496 String[] vals = { FIELD_COMBINE_PARAM_AND, FIELD_COMBINE_PARAM_OR, FIELD_COMBINE_PARAM_NOT };
497 String[] val_texts = { getTextString("param." + FIELD_COMBINE_PARAM + "." + FIELD_COMBINE_PARAM_AND, lang), getTextString("param." + FIELD_COMBINE_PARAM + "." + FIELD_COMBINE_PARAM_OR, lang), getTextString("param." + FIELD_COMBINE_PARAM + "." + FIELD_COMBINE_PARAM_NOT, lang) };
498
499 param = GSXML.createParameterDescription(doc, FIELD_COMBINE_PARAM, "", GSXML.PARAM_TYPE_ENUM_SINGLE, param_default, vals, val_texts);
500 param.setAttribute(GSXML.PARAM_IGNORE_POS_ATT, "0");
501 }
502
503 if (param != null)
504 {
505 param_list.appendChild(param);
506 }
507 else
508 {
509 super.createParameter(name, param_list, lang);
510 }
511 }
512
513 // should cache some of this
514 protected void getLevelData(ArrayList<String> level_ids, ArrayList<String> level_names, String lang)
515 {
516 Element level_list = (Element) GSXML.getChildByTagName(this.config_info, LEVEL_ELEM + GSXML.LIST_MODIFIER);
517 NodeList levels = level_list.getElementsByTagName(LEVEL_ELEM);
518 for (int i = 0; i < levels.getLength(); i++)
519 {
520 Element level = (Element) levels.item(i);
521 String shortname = level.getAttribute(GSXML.SHORTNAME_ATT);
522 if (shortname.equals(""))
523 {
524 continue;
525 }
526 level_ids.add(shortname);
527 String display_name = GSXML.getDisplayText(level, GSXML.DISPLAY_TEXT_NAME, lang, "en");
528 if (display_name.equals(""))
529 {
530 // we'll use the name, and the dictionary
531 display_name = level.getAttribute(GSXML.NAME_ATT);
532 if (display_name.equals(""))
533 {
534 display_name = shortname;
535 }
536 else
537 {
538 display_name = getTextString("level." + display_name, lang);
539 }
540 }
541 level_names.add(display_name);
542 }
543 }
544
545 // the following three functions are needed so the base class can
546 // call the process+SERVICE_NAME methods
547 /** process a text query */
548 protected Element processTextQuery(Element request)
549 {
550 return processAnyQuery(request, TEXT_QUERY);
551 }
552
553 /** process a field query */
554 protected Element processFieldQuery(Element request)
555 {
556 return processAnyQuery(request, SIMPLE_QUERY);
557 }
558
559 /** process an advanced field query */
560 protected Element processAdvancedFieldQuery(Element request)
561 {
562 return processAnyQuery(request, ADVANCED_QUERY);
563 }
564
565 protected Element processRawQuery(Element request)
566 {
567 return processAnyQuery(request, RAW_QUERY);
568 }
569
570 /** process a query */
571 protected Element processAnyQuery(Element request, int query_type)
572 {
573 String service_name = null;
574 String empty_query_test_param = null;
575 // set up the type specific bits
576 switch (query_type)
577 {
578 case TEXT_QUERY:
579 service_name = QUERY_SERVICE;
580 empty_query_test_param = QUERY_PARAM;
581 break;
582 case SIMPLE_QUERY:
583 service_name = FIELD_QUERY_SERVICE;
584 empty_query_test_param = FIELD_QUERY_PARAM;
585 break;
586 case ADVANCED_QUERY:
587 service_name = ADVANCED_FIELD_QUERY_SERVICE;
588 empty_query_test_param = FIELD_QUERY_PARAM;
589 break;
590 case RAW_QUERY:
591 service_name = RAW_QUERY_SERVICE;
592 empty_query_test_param = RAW_PARAM;
593 break;
594 default:
595 // should never get here
596 logger.error("wrong query type!!");
597 return null;
598 }
599
600 // Create a new (empty) result message
601 Document result_doc = XMLConverter.newDOM();
602 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
603 result.setAttribute(GSXML.FROM_ATT, service_name);
604 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
605
606 // Get the parameters of the request
607 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
608 if (param_list == null)
609 {
610 logger.error("TextQuery request had no paramList.");
611 return result; // Return the empty result
612 }
613
614 // Process the request parameters
615 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
616
617 // Make sure a query has been specified
618 String query = (String) params.get(empty_query_test_param);
619 if (query == null || query.equals(""))
620 {
621 return result; // Return the empty result
622 }
623
624 // If a field hasn't been specified, use the default - for textQuery
625 String field = (String) params.get(INDEX_PARAM);
626 if (field == null)
627 {
628 field = default_index;
629 }
630
631 // set up the appropriate query system
632 if (!setUpQueryer(params))
633 {
634 return result;
635 }
636
637 // if field search, create the query string
638 switch (query_type)
639 {
640 case TEXT_QUERY:
641 query = addFieldInfo(query, field);
642 break;
643 case SIMPLE_QUERY:
644 query = parseFieldQueryParams(params);
645 break;
646 case ADVANCED_QUERY:
647 query = parseAdvancedFieldQueryParams(params);
648 break;
649 }
650
651 // run the query
652 Object query_result = runQuery(query);
653
654 // build up the response
655
656 // Create a metadata list to store information about the query results
657 // should we be using metadataList? or something else?
658 Element metadata_list = result_doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
659 result.appendChild(metadata_list);
660
661 // Add a metadata element specifying the number of matching documents
662 long totalDocs = numDocsMatched(query_result);
663
664 GSXML.addMetadata(metadata_list, "numDocsMatched", "" + totalDocs);
665
666 // Create a document list to store the matching documents, and add them
667 String[] docs = getDocIDs(query_result);
668 String[] doc_ranks = getDocRanks(query_result);
669
670 // add a metadata item to specify docs returned
671 int docs_returned = docs.length;
672 if (does_paging)
673 {
674 String maxdocs_str = (String) params.get(MAXDOCS_PARAM);
675 if (maxdocs_str != null)
676 {
677 int maxdocs = Integer.parseInt(maxdocs_str);
678 docs_returned = (maxdocs < (int) totalDocs ? maxdocs : (int) totalDocs);
679 }
680 }
681 GSXML.addMetadata(metadata_list, "numDocsReturned", "" + docs_returned);
682
683 // add a metadata item to specify what actual query was done - eg if stuff was stripped out etc. and then we can use the query later, cos we don't know which parameter was the query
684 GSXML.addMetadata(metadata_list, "query", query);
685 if (docs.length > 0)
686 {
687 Element document_list = result_doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
688 result.appendChild(document_list);
689 for (int d = 0; d < docs.length; d++)
690 {
691 String doc_id = internalNum2OID(docs[d]);
692 Element doc_node = createDocNode(result_doc, doc_id, doc_ranks[d]);
693 document_list.appendChild(doc_node);
694 }
695 }
696
697 // Create a term list to store the term information, and add it
698 Element term_list = result_doc.createElement(GSXML.TERM_ELEM + GSXML.LIST_MODIFIER);
699 result.appendChild(term_list);
700 addTermInfo(term_list, params, query_result);
701
702 if(does_faceting)
703 {
704 ArrayList<FacetWrapper> facets = getFacets(query_result);
705 if(facets != null)
706 {
707 Element facet_list = result_doc.createElement(GSXML.FACET_ELEM + GSXML.LIST_MODIFIER);
708 result.appendChild(facet_list);
709
710 for(FacetWrapper currentFacet : facets)
711 {
712 Element facet_elem = result_doc.createElement(GSXML.FACET_ELEM);
713 facet_elem.setAttribute(GSXML.NAME_ATT, currentFacet.getName());
714 facet_list.appendChild(facet_elem);
715
716 HashMap<String, Long> countMap = currentFacet.getCounts();
717
718 for(String countName : countMap.keySet())
719 {
720 long countValue = countMap.get(countName);
721 if(countValue > 0)
722 {
723 Element count_elem = result_doc.createElement(GSXML.COUNT_ELEM);
724 count_elem.setAttribute(GSXML.NAME_ATT, countName);
725 count_elem.setTextContent("" + countValue);
726
727 facet_elem.appendChild(count_elem);
728 }
729 }
730 }
731 }
732 }
733
734 return result;
735
736 }
737
738 /** methods to handle actually doing the query */
739 /** do any initialisation of the query object */
740 abstract protected boolean setUpQueryer(HashMap<String, Serializable> params);
741
742 /** do the query */
743 abstract protected Object runQuery(String query);
744
745 /** get the total number of docs that match */
746 abstract protected long numDocsMatched(Object query_result);
747
748 /** get the list of doc ids */
749 abstract protected String[] getDocIDs(Object query_result);
750
751 /** get the list of doc ranks */
752 abstract protected String[] getDocRanks(Object query_result);
753
754 /** get the list of facets */
755 abstract protected ArrayList<FacetWrapper> getFacets(Object query_result);
756
757 /** add in term info if available */
758 abstract protected boolean addTermInfo(Element term_list, HashMap<String, Serializable> params, Object query_result);
759
760 /**
761 * combines all the field params into a single query - for simple field
762 * query
763 */
764 /** We assume the combination (AND/OR) is done by the match param */
765 protected String parseFieldQueryParams(HashMap<String, Serializable> params)
766 {
767
768 StringBuffer final_query = new StringBuffer(256);
769 String text_line = (String) params.get(FIELD_QUERY_PARAM);
770 String[] texts = text_line.split(",", -1);
771 String field_line = (String) params.get(FIELD_FIELD_PARAM);
772 String[] fields = field_line.split(",", -1);
773
774 for (int i = 0; i < texts.length; i++)
775 {
776 String q = texts[i].trim();
777 if (!q.equals(""))
778 {
779 final_query.append(" " + addFieldInfo(q, fields[i]));
780 }
781 }
782
783 return final_query.toString();
784 }
785
786 abstract protected String addFieldInfo(String query, String field);
787
788 /**
789 * combines all the field params into a single query - for advanced field
790 * query
791 */
792 protected String parseAdvancedFieldQueryParams(HashMap<String, Serializable> params)
793 {
794
795 StringBuffer final_query = new StringBuffer(256);
796 String text_line = (String) params.get(FIELD_QUERY_PARAM);
797 String[] texts = text_line.split(",", -1);
798 String field_line = (String) params.get(FIELD_FIELD_PARAM);
799 String[] fields = field_line.split(",", -1);
800 String[] cases = null;
801 String[] stems = null;
802 String[] accents = null;
803 if (does_case)
804 {
805 String case_line = (String) params.get(FIELD_CASE_PARAM);
806 if (case_line != null)
807 cases = case_line.split(",", -1);
808 }
809 if (does_stem)
810 {
811 String stem_line = (String) params.get(FIELD_STEM_PARAM);
812 if (stem_line != null)
813 stems = stem_line.split(",", -1);
814 }
815 if (does_accent)
816 {
817 String accent_line = (String) params.get(FIELD_ACCENT_PARAM);
818 if (accent_line != null)
819 accents = accent_line.split(",", -1);
820 }
821 String combine_line = (String) params.get(FIELD_COMBINE_PARAM);
822 String[] combines = combine_line.split(",", -1);
823 String combine = "";
824 for (int i = 0; i < texts.length; i++)
825 {
826 if (i == 0)
827 {// assume first one is blank
828 combine = "";
829 }
830 else
831 {
832 String x = combines[i];
833 if (x.equals(FIELD_COMBINE_PARAM_AND))
834 {
835 combine = AND_OPERATOR;
836 }
837 else if (x.equals(FIELD_COMBINE_PARAM_OR))
838 {
839 combine = OR_OPERATOR;
840 }
841 else if (x.equals(FIELD_COMBINE_PARAM_NOT))
842 {
843 combine = NOT_OPERATOR;
844 }
845
846 }
847
848 String q = texts[i].trim();
849 boolean modified = false;
850 if (!q.equals(""))
851 {
852 String c = null;
853 String s = null;
854 String a = null;
855 if (does_case)
856 {
857 modified = true;
858 c = cases[i];
859 }
860 if (does_stem)
861 {
862 modified = true;
863 s = stems[i];
864 }
865 if (does_accent)
866 {
867 modified = true;
868 a = accents[i];
869 }
870 if (modified)
871 {
872 q = addStemOptions(q, s, c, a);
873 }
874 addQueryElem(final_query, q, fields[i], combine);
875 }
876 }
877 return final_query.toString();
878 }
879
880 abstract protected void addQueryElem(StringBuffer final_query, String query, String field, String combine);
881
882 abstract protected String addStemOptions(String query, String stem, String casef, String accent);
883
884}
Note: See TracBrowser for help on using the repository browser.