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

Last change on this file since 32547 was 32547, checked in by kjdon, 5 years ago

paramDefault elements for searching can now go in the format element instead. This makes them in hte same place as for display. Also means you can edit them in gli

  • Property svn:keywords set to Author Date Id Revision
File size: 32.8 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 = search_elem.getElementsByTagName(GSXML.PARAM_DEFAULT_ELEM); //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.