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

Last change on this file since 32453 was 32453, checked in by kjdon, 6 years ago

replacing hard coded param names with static string variables. set up save params for those params we need to save to the session.

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