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

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

Fixing Greenstone 3's use (or lack thereof) of generics, this was done automatically so we may want to change it over time. This change will also auto-format any files that have not already been formatted.

  • Property svn:keywords set to Author Date Id Revision
File size: 26.2 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 org.greenstone.gsdl3.util.*;
22
23// XML classes
24import org.w3c.dom.Document;
25import org.w3c.dom.Element;
26import org.w3c.dom.NodeList;
27
28// java classes
29import java.util.Iterator;
30import java.util.Set;
31import java.util.HashMap;
32import java.util.Map;
33import java.util.ArrayList;
34import java.util.Vector;
35import java.io.File;
36import java.io.Serializable;
37
38import org.apache.log4j.*;
39
40abstract public class AbstractGS2FieldSearch extends AbstractGS2TextSearch
41{
42 // extra services offered by mgpp collections
43 protected static final String FIELD_QUERY_SERVICE = "FieldQuery";
44 protected static final String ADVANCED_FIELD_QUERY_SERVICE = "AdvancedFieldQuery";
45 protected static final String RAW_QUERY_SERVICE = "RawQuery";
46
47 // extra parameters used
48 protected static final String LEVEL_PARAM = "level";
49 protected static final String RANK_PARAM = "sortBy";
50 protected static final String RANK_PARAM_RANK = "1";
51 protected static final String RANK_PARAM_NONE = "0";
52 protected static final String SIMPLE_FIELD_PARAM = "simpleField";
53 protected static final String ADVANCED_FIELD_PARAM = "complexField";
54
55 protected static final String RAW_PARAM = "rawquery";
56
57 // more params for field query
58 protected static final String FIELD_QUERY_PARAM = "fqv";
59 protected static final String FIELD_STEM_PARAM = "fqs";
60 protected static final String FIELD_CASE_PARAM = "fqc";
61 protected static final String FIELD_ACCENT_PARAM = "fqa";
62 protected static final String FIELD_FIELD_PARAM = "fqf";
63 protected static final String FIELD_COMBINE_PARAM = "fqk";
64 protected static final String FIELD_COMBINE_PARAM_AND = "0";
65 protected static final String FIELD_COMBINE_PARAM_OR = "1";
66 protected static final String FIELD_COMBINE_PARAM_NOT = "2";
67
68 // some stuff for config files
69 protected static final String SEARCH_TYPE_ELEM = "searchType";
70 protected static final String SEARCH_TYPE_PLAIN = "plain";
71 protected static final String SEARCH_TYPE_SIMPLE_FORM = "simpleform";
72 protected static final String SEARCH_TYPE_ADVANCED_FORM = "advancedform";
73 protected static final String SEARCH_TYPE_RAW = "raw";
74
75 protected static final String DEFAULT_LEVEL_ELEM = "defaultLevel";
76 protected static final String DEFAULT_DB_LEVEL_ELEM = "defaultDBLevel";
77 protected static final String LEVEL_ELEM = "level";
78 protected static final String FIELD_ATT = "field";
79
80 protected static final int TEXT_QUERY = 0;
81 protected static final int SIMPLE_QUERY = 1;
82 protected static final int ADVANCED_QUERY = 2;
83 protected static final int RAW_QUERY = 3;
84
85 protected String AND_OPERATOR = "&";
86 protected String OR_OPERATOR = "|";
87 protected String NOT_OPERATOR = "!";
88
89 // the default level for searching
90 protected String default_level = null;
91 // default level for collection db
92 protected String default_db_level = null;
93 // which search services will we offer??
94 protected boolean plain_search = false;
95 protected boolean simple_form_search = false;
96 protected boolean advanced_form_search = false;
97 protected boolean raw_search = false;
98
99 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractGS2FieldSearch.class.getName());
100
101 /** constructor */
102 public AbstractGS2FieldSearch()
103 {
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
191 Document owner = info.getOwnerDocument();
192
193 NodeList levels = info.getElementsByTagName(GSXML.LEVEL_ELEM);
194
195 for (int i = 0; i < levels.getLength(); i++)
196 {
197 Element lev = (Element) levels.item(i);
198 String name = lev.getAttribute(GSXML.NAME_ATT);
199 Element node_extra = GSXML.getNamedElement(config_search, GSXML.LEVEL_ELEM, GSXML.NAME_ATT, name);
200 if (node_extra == null)
201 {
202 logger.error("haven't found extra info for level named " + name);
203 continue;
204 }
205
206 // get the display elements if any - displayName
207 NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
208 if (display_names != null)
209 {
210 for (int j = 0; j < display_names.getLength(); j++)
211 {
212 Element e = (Element) display_names.item(j);
213 lev.appendChild(owner.importNode(e, true));
214 }
215 }
216 } // for each level
217 }
218 else
219 {
220 // for soem reason we don't have the collectionConfig file. assume plain only
221 this.plain_search = true;
222 }
223
224 // the format info is the same for all services
225 Element format_info = (Element) format_info_map.get(QUERY_SERVICE);
226
227 // set up the extra services which are available for this collection
228 if (this.simple_form_search)
229 {
230 // set up short_service_info_ - for now just has id and type - name will be added in on the fly
231 Element fq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
232 fq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
233 fq_service.setAttribute(GSXML.NAME_ATT, FIELD_QUERY_SERVICE);
234 this.short_service_info.appendChild(fq_service);
235
236 if (format_info != null)
237 {
238 this.format_info_map.put(FIELD_QUERY_SERVICE, format_info);
239 }
240 }
241
242 if (this.advanced_form_search)
243 {
244 Element afq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
245 afq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
246 afq_service.setAttribute(GSXML.NAME_ATT, ADVANCED_FIELD_QUERY_SERVICE);
247 this.short_service_info.appendChild(afq_service);
248
249 if (format_info != null)
250 {
251 this.format_info_map.put(ADVANCED_FIELD_QUERY_SERVICE, format_info);
252 }
253 }
254
255 if (this.raw_search)
256 {
257 Element rq_service = this.doc.createElement(GSXML.SERVICE_ELEM);
258 rq_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
259 rq_service.setAttribute(GSXML.NAME_ATT, RAW_QUERY_SERVICE);
260 this.short_service_info.appendChild(rq_service);
261
262 if (format_info != null)
263 {
264 this.format_info_map.put(RAW_QUERY_SERVICE, format_info);
265 }
266 }
267
268 return true;
269 }
270
271 protected Element getServiceDescription(String service_id, String lang, String subset)
272 {
273 // should we check that the service is actually on offer? presumably we wont get asked for services that we haven't advertised previously.
274
275 if (!service_id.equals(FIELD_QUERY_SERVICE) && !service_id.equals(ADVANCED_FIELD_QUERY_SERVICE) && !service_id.equals(RAW_QUERY_SERVICE))
276 {
277 return super.getServiceDescription(service_id, lang, subset);
278 }
279
280 Element service = this.doc.createElement(GSXML.SERVICE_ELEM);
281 service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_QUERY);
282 service.setAttribute(GSXML.NAME_ATT, service_id);
283 if (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER))
284 {
285 service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getTextString(service_id + ".name", lang)));
286 service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_SUBMIT, getTextString(service_id + ".submit", lang)));
287 service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(service_id + ".description", lang)));
288
289 }
290 if (subset == null || subset.equals(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER))
291 {
292 Element param_list = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
293 service.appendChild(param_list);
294 if (service_id.equals(FIELD_QUERY_SERVICE))
295 {
296
297 addCustomQueryParams(param_list, lang);
298 createParameter(MAXDOCS_PARAM, param_list, lang);
299 if (!default_index_subcollection.equals(""))
300 {
301 createParameter(INDEX_SUBCOLLECTION_PARAM, param_list, lang);
302 }
303 if (!default_index_language.equals(""))
304 {
305 createParameter(INDEX_LANGUAGE_PARAM, param_list, lang);
306 }
307 // create a multi param for the fields etc
308 // text box, field
309 Element multiparam = null;
310 Element param = null;
311 multiparam = GSXML.createParameterDescription(this.doc, SIMPLE_FIELD_PARAM, "", GSXML.PARAM_TYPE_MULTI, null, null, null);
312 multiparam.setAttribute("occurs", "4");
313 param_list.appendChild(multiparam);
314
315 // the components
316
317 createParameter(FIELD_QUERY_PARAM, multiparam, lang);
318 createParameter(FIELD_FIELD_PARAM, multiparam, lang);
319
320 }
321 else if (service_id.equals(ADVANCED_FIELD_QUERY_SERVICE))
322 {
323 createParameter(LEVEL_PARAM, param_list, lang);
324 createParameter(RANK_PARAM, param_list, lang);
325 createParameter(MAXDOCS_PARAM, param_list, lang);
326 if (!default_index_subcollection.equals(""))
327 {
328 createParameter(INDEX_SUBCOLLECTION_PARAM, param_list, lang);
329 }
330 if (!default_index_language.equals(""))
331 {
332 createParameter(INDEX_LANGUAGE_PARAM, param_list, lang);
333 }
334
335 // create a multi param for the fields etc
336 // text box, stem, case, field
337
338 Element multiparam = null;
339 Element param = null;
340
341 multiparam = GSXML.createParameterDescription(this.doc, ADVANCED_FIELD_PARAM, "", GSXML.PARAM_TYPE_MULTI, null, null, null);
342 multiparam.setAttribute("occurs", "4");
343 param_list.appendChild(multiparam);
344
345 createParameter(FIELD_COMBINE_PARAM, multiparam, lang);
346 createParameter(FIELD_QUERY_PARAM, multiparam, lang);
347 if (this.does_case)
348 {
349 createParameter(FIELD_CASE_PARAM, multiparam, lang);
350 }
351 if (this.does_stem)
352 {
353 createParameter(FIELD_STEM_PARAM, multiparam, lang);
354 }
355 if (this.does_accent)
356 {
357 createParameter(FIELD_ACCENT_PARAM, multiparam, lang);
358 }
359 createParameter(FIELD_FIELD_PARAM, multiparam, lang);
360
361 }
362 else if (service_id.equals(RAW_QUERY_SERVICE))
363 {
364 if (does_chunking)
365 {
366 createParameter(MAXDOCS_PARAM, param_list, lang);
367 }
368 if (does_paging)
369 {
370 createParameter(HITS_PER_PAGE_PARAM, param_list, lang);
371 createParameter(START_PAGE_PARAM, param_list, lang);
372 }
373 createParameter(RAW_PARAM, param_list, lang);
374 service.appendChild(param_list);
375 }
376 }
377 return service;
378
379 }
380
381 /** add in the level params to TextQuery */
382 protected void addCustomQueryParams(Element param_list, String lang)
383 {
384 createParameter(LEVEL_PARAM, param_list, lang);
385 super.addCustomQueryParams(param_list, lang);
386 }
387
388 /** create a param and add to the list */
389 protected void createParameter(String name, Element param_list, String lang)
390 {
391 Element param = null;
392 if (name.equals(LEVEL_PARAM))
393 {
394 ArrayList<String> level_ids = new ArrayList<String>();
395 ArrayList<String> level_names = new ArrayList<String>();
396 getLevelData(level_ids, level_names, lang);
397 if (level_ids.size() > 1)
398 {
399 // the first one is the default
400 //param = GSXML.createParameterDescription2(this.doc, LEVEL_PARAM, getTextString("param."+LEVEL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)level_ids.get(0), level_ids, level_names);
401 param = GSXML.createParameterDescription2(this.doc, LEVEL_PARAM, getTextString("param." + LEVEL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, this.default_level, level_ids, level_names);
402 }
403 else
404 {
405 // we need to set the level, but hidden, in case there is an invalid level saved
406 //param = GSXML.createParameterDescription(this.doc, LEVEL_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, (String)level_ids.get(0), null, null);
407 param = GSXML.createParameterDescription(this.doc, LEVEL_PARAM, "", GSXML.PARAM_TYPE_INVISIBLE, this.default_level, null, null);
408 }
409 }
410 else if (name.equals(RANK_PARAM))
411 {
412 String[] vals1 = { RANK_PARAM_RANK, RANK_PARAM_NONE };
413 String[] vals1_texts = { getTextString("param." + RANK_PARAM + "." + RANK_PARAM_RANK, lang), getTextString("param." + RANK_PARAM + "." + RANK_PARAM_NONE, lang) };
414
415 param = GSXML.createParameterDescription(this.doc, RANK_PARAM, getTextString("param." + RANK_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, RANK_PARAM_RANK, vals1, vals1_texts);
416
417 }
418 else if (name.equals(FIELD_QUERY_PARAM))
419 {
420 param = GSXML.createParameterDescription(this.doc, FIELD_QUERY_PARAM, getTextString("param." + FIELD_QUERY_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
421
422 }
423 else if (name.equals(FIELD_CASE_PARAM) || name.equals(FIELD_STEM_PARAM) || name.equals(FIELD_ACCENT_PARAM))
424 {
425 String[] bool_ops = { "0", "1" };
426 String[] bool_texts = { getTextString("param.boolean.off", lang, "AbstractTextSearch"), getTextString("param.boolean.on", lang, "AbstractTextSearch") };
427 param = GSXML.createParameterDescription(this.doc, name, getTextString("param." + name, lang), GSXML.PARAM_TYPE_BOOLEAN, BOOLEAN_PARAM_ON, bool_ops, bool_texts);
428
429 }
430 else if (name.equals(FIELD_FIELD_PARAM))
431 {
432 ArrayList<String> fields = new ArrayList<String>();
433 ArrayList<String> field_names = new ArrayList<String>();
434 getIndexData(fields, field_names, lang);
435 // the field list - read from config file
436
437 // Fix for http://trac.greenstone.org/ticket/245 "java crash, index out of bounds"
438 // org.greenstone.gsdl3.service.AbstractGS2FieldSearch.createParameter(AbstractGS2FieldSearch.java:362)
439 // Changed from:
440 // param = GSXML.createParameterDescription2(this.doc, name, getTextString("param."+name, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, (String)fields.get(0), fields, field_names );
441 String default_value = (fields.size() > 0) ? fields.get(0) : null;
442 // don't want to access element 0 if fields.size()==0, and
443 // GSXML.createParameterDescription2 checks for default_value==null condition
444 param = GSXML.createParameterDescription2(this.doc, name, getTextString("param." + name, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, default_value, fields, field_names);
445
446 }
447 else if (name.equals(FIELD_COMBINE_PARAM))
448 {
449
450 String[] vals = { FIELD_COMBINE_PARAM_AND, FIELD_COMBINE_PARAM_OR, FIELD_COMBINE_PARAM_NOT };
451 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) };
452
453 param = GSXML.createParameterDescription(this.doc, FIELD_COMBINE_PARAM, "", GSXML.PARAM_TYPE_ENUM_SINGLE, FIELD_COMBINE_PARAM_AND, vals, val_texts);
454 param.setAttribute(GSXML.PARAM_IGNORE_POS_ATT, "0");
455 }
456
457 if (param != null)
458 {
459 param_list.appendChild(param);
460 }
461 else
462 {
463 super.createParameter(name, param_list, lang);
464 }
465 }
466
467 // should cache some of this
468 protected void getLevelData(ArrayList<String> level_ids, ArrayList<String> level_names, String lang)
469 {
470 Element level_list = (Element) GSXML.getChildByTagName(this.config_info, LEVEL_ELEM + GSXML.LIST_MODIFIER);
471 NodeList levels = level_list.getElementsByTagName(LEVEL_ELEM);
472 for (int i = 0; i < levels.getLength(); i++)
473 {
474 Element level = (Element) levels.item(i);
475 String shortname = level.getAttribute(GSXML.SHORTNAME_ATT);
476 if (shortname.equals(""))
477 {
478 continue;
479 }
480 level_ids.add(shortname);
481 String display_name = GSXML.getDisplayText(level, GSXML.DISPLAY_TEXT_NAME, lang, "en");
482 if (display_name.equals(""))
483 {
484 // we'll use the name, and the dictionary
485 display_name = level.getAttribute(GSXML.NAME_ATT);
486 if (display_name.equals(""))
487 {
488 display_name = shortname;
489 }
490 else
491 {
492 display_name = getTextString("level." + display_name, lang);
493 }
494 }
495 level_names.add(display_name);
496 }
497 }
498
499 // the following three functions are needed so the base class can
500 // call the process+SERVICE_NAME methods
501 /** process a text query */
502 protected Element processTextQuery(Element request)
503 {
504 return processAnyQuery(request, TEXT_QUERY);
505 }
506
507 /** process a field query */
508 protected Element processFieldQuery(Element request)
509 {
510 return processAnyQuery(request, SIMPLE_QUERY);
511 }
512
513 /** process an advanced field query */
514 protected Element processAdvancedFieldQuery(Element request)
515 {
516 return processAnyQuery(request, ADVANCED_QUERY);
517 }
518
519 protected Element processRawQuery(Element request)
520 {
521 return processAnyQuery(request, RAW_QUERY);
522 }
523
524 /** process a query */
525 protected Element processAnyQuery(Element request, int query_type)
526 {
527 String service_name = null;
528 String empty_query_test_param = null;
529 // set up the type specific bits
530 switch (query_type)
531 {
532 case TEXT_QUERY:
533 service_name = QUERY_SERVICE;
534 empty_query_test_param = QUERY_PARAM;
535 break;
536 case SIMPLE_QUERY:
537 service_name = FIELD_QUERY_SERVICE;
538 empty_query_test_param = FIELD_QUERY_PARAM;
539 break;
540 case ADVANCED_QUERY:
541 service_name = ADVANCED_FIELD_QUERY_SERVICE;
542 empty_query_test_param = FIELD_QUERY_PARAM;
543 break;
544 case RAW_QUERY:
545 service_name = RAW_QUERY_SERVICE;
546 empty_query_test_param = RAW_PARAM;
547 break;
548 default:
549 // should never get here
550 logger.error("wrong query type!!");
551 return null;
552 }
553
554 // Create a new (empty) result message
555 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
556 result.setAttribute(GSXML.FROM_ATT, service_name);
557 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
558
559 // Get the parameters of the request
560 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
561 if (param_list == null)
562 {
563 logger.error("TextQuery request had no paramList.");
564 return result; // Return the empty result
565 }
566
567 // Process the request parameters
568 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
569
570 // Make sure a query has been specified
571 String query = (String) params.get(empty_query_test_param);
572 if (query == null || query.equals(""))
573 {
574 return result; // Return the empty result
575 }
576
577 // If a field hasn't been specified, use the default - for textQuery
578 String field = (String) params.get(INDEX_PARAM);
579 if (field == null)
580 {
581 field = default_index;
582 }
583
584 // set up the appropriate query system
585 if (!setUpQueryer(params))
586 {
587 return result;
588 }
589
590 // if field search, create the query string
591 switch (query_type)
592 {
593 case TEXT_QUERY:
594 query = addFieldInfo(query, field);
595 break;
596 case SIMPLE_QUERY:
597 query = parseFieldQueryParams(params);
598 break;
599 case ADVANCED_QUERY:
600 query = parseAdvancedFieldQueryParams(params);
601 break;
602 }
603
604 // run the query
605 Object query_result = runQuery(query);
606
607 // build up the response
608
609 // Create a metadata list to store information about the query results
610 // should we be using metadataList? or something else?
611 Element metadata_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
612 result.appendChild(metadata_list);
613
614 // Add a metadata element specifying the number of matching documents
615 long totalDocs = numDocsMatched(query_result);
616
617 GSXML.addMetadata(this.doc, metadata_list, "numDocsMatched", "" + totalDocs);
618
619 // Create a document list to store the matching documents, and add them
620 String[] docs = getDocIDs(query_result);
621 String[] doc_ranks = getDocRanks(query_result);
622
623 // add a metadata item to specify docs returned
624 int docs_returned = docs.length;
625 if (does_paging)
626 {
627 String maxdocs_str = (String) params.get(MAXDOCS_PARAM);
628 if (maxdocs_str != null)
629 {
630 int maxdocs = Integer.parseInt(maxdocs_str);
631 docs_returned = (maxdocs < (int) totalDocs ? maxdocs : (int) totalDocs);
632 }
633 }
634 GSXML.addMetadata(this.doc, metadata_list, "numDocsReturned", "" + docs_returned);
635
636 // 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
637 GSXML.addMetadata(this.doc, metadata_list, "query", query);
638 if (docs.length > 0)
639 {
640 Element document_list = this.doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
641 result.appendChild(document_list);
642 for (int d = 0; d < docs.length; d++)
643 {
644 String doc_id = internalNum2OID(docs[d]);
645 Element doc_node = createDocNode(doc_id, doc_ranks[d]);
646 document_list.appendChild(doc_node);
647 }
648 }
649
650 // Create a term list to store the term information, and add it
651 Element term_list = this.doc.createElement(GSXML.TERM_ELEM + GSXML.LIST_MODIFIER);
652 result.appendChild(term_list);
653 addTermInfo(term_list, params, query_result);
654
655 return result;
656
657 }
658
659 /** methods to handle actually doing the query */
660 /** do any initialisation of the query object */
661 abstract protected boolean setUpQueryer(HashMap<String, Serializable> params);
662
663 /** do the query */
664 abstract protected Object runQuery(String query);
665
666 /** get the total number of docs that match */
667 abstract protected long numDocsMatched(Object query_result);
668
669 /** get the list of doc ids */
670 abstract protected String[] getDocIDs(Object query_result);
671
672 /** get the list of doc ranks */
673 abstract protected String[] getDocRanks(Object query_result);
674
675 /** add in term info if available */
676 abstract protected boolean addTermInfo(Element term_list, HashMap<String, Serializable> params, Object query_result);
677
678 /**
679 * combines all the field params into a single query - for simple field
680 * query
681 */
682 /** We assume the combination (AND/OR) is done by the match param */
683 protected String parseFieldQueryParams(HashMap<String, Serializable> params)
684 {
685
686 StringBuffer final_query = new StringBuffer(256);
687 String text_line = (String) params.get(FIELD_QUERY_PARAM);
688 String[] texts = text_line.split(",", -1);
689 String field_line = (String) params.get(FIELD_FIELD_PARAM);
690 String[] fields = field_line.split(",", -1);
691
692 for (int i = 0; i < texts.length; i++)
693 {
694 String q = texts[i].trim();
695 if (!q.equals(""))
696 {
697 final_query.append(" " + addFieldInfo(q, fields[i]));
698 }
699 }
700
701 return final_query.toString();
702 }
703
704 abstract protected String addFieldInfo(String query, String field);
705
706 /**
707 * combines all the field params into a single query - for advanced field
708 * query
709 */
710 protected String parseAdvancedFieldQueryParams(HashMap<String, Serializable> params)
711 {
712
713 StringBuffer final_query = new StringBuffer(256);
714 String text_line = (String) params.get(FIELD_QUERY_PARAM);
715 String[] texts = text_line.split(",", -1);
716 String field_line = (String) params.get(FIELD_FIELD_PARAM);
717 String[] fields = field_line.split(",", -1);
718 String[] cases = null;
719 String[] stems = null;
720 String[] accents = null;
721 if (does_case)
722 {
723 String case_line = (String) params.get(FIELD_CASE_PARAM);
724 if (case_line != null)
725 cases = case_line.split(",", -1);
726 }
727 if (does_stem)
728 {
729 String stem_line = (String) params.get(FIELD_STEM_PARAM);
730 if (stem_line != null)
731 stems = stem_line.split(",", -1);
732 }
733 if (does_accent)
734 {
735 String accent_line = (String) params.get(FIELD_ACCENT_PARAM);
736 if (accent_line != null)
737 accents = accent_line.split(",", -1);
738 }
739 String combine_line = (String) params.get(FIELD_COMBINE_PARAM);
740 String[] combines = combine_line.split(",", -1);
741 String combine = "";
742 for (int i = 0; i < texts.length; i++)
743 {
744 if (i == 0)
745 {// assume first one is blank
746 combine = "";
747 }
748 else
749 {
750 String x = combines[i];
751 if (x.equals(FIELD_COMBINE_PARAM_AND))
752 {
753 combine = AND_OPERATOR;
754 }
755 else if (x.equals(FIELD_COMBINE_PARAM_OR))
756 {
757 combine = OR_OPERATOR;
758 }
759 else if (x.equals(FIELD_COMBINE_PARAM_NOT))
760 {
761 combine = NOT_OPERATOR;
762 }
763
764 }
765
766 String q = texts[i].trim();
767 boolean modified = false;
768 if (!q.equals(""))
769 {
770 String c = null;
771 String s = null;
772 String a = null;
773 if (does_case)
774 {
775 modified = true;
776 c = cases[i];
777 }
778 if (does_stem)
779 {
780 modified = true;
781 s = stems[i];
782 }
783 if (does_accent)
784 {
785 modified = true;
786 a = accents[i];
787 }
788 if (modified)
789 {
790 q = addStemOptions(q, s, c, a);
791 }
792 addQueryElem(final_query, q, fields[i], combine);
793 }
794 }
795 return final_query.toString();
796 }
797
798 abstract protected void addQueryElem(StringBuffer final_query, String query, String field, String combine);
799
800 abstract protected String addStemOptions(String query, String stem, String casef, String accent);
801
802}
Note: See TracBrowser for help on using the repository browser.