001: //=== Copyright (C) 2001-2005 Food and Agriculture Organization of the
002: //=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
003: //=== and United Nations Environment Programme (UNEP)
004: //===
005: //=== This program is free software; you can redistribute it and/or modify
006: //=== it under the terms of the GNU General Public License as published by
007: //=== the Free Software Foundation; either version 2 of the License, or (at
008: //=== your option) any later version.
009: //===
010: //=== This program is distributed in the hope that it will be useful, but
011: //=== WITHOUT ANY WARRANTY; without even the implied warranty of
012: //=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: //=== General Public License for more details.
014: //===
015: //=== You should have received a copy of the GNU General Public License
016: //=== along with this program; if not, write to the Free Software
017: //=== Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: //===
019: //=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
020: //=== Rome - Italy. email: GeoNetwork@fao.org
021: //==============================================================================
022:
023: package org.fao.geonet.kernel.search;
024:
025: import java.util.ArrayList;
026: import java.util.Collections;
027: import java.util.Comparator;
028: import java.util.Hashtable;
029: import java.util.Enumeration;
030: import java.util.List;
031: import java.util.Vector;
032:
033: import jeeves.server.context.ServiceContext;
034: import jeeves.utils.Util;
035:
036: import org.fao.geonet.kernel.Thesaurus;
037: import org.fao.geonet.kernel.ThesaurusManager;
038: import org.fao.geonet.kernel.KeywordBean;
039: import org.jdom.Element;
040: import org.openrdf.model.Value;
041: import org.openrdf.sesame.query.QueryResultsTable;
042:
043: public class KeywordsSearcher {
044: private ThesaurusManager _tm;
045:
046: private String _query;
047: private String _lang;
048: private String _sortBy = "label";
049: private String _sortOrder = "ascending";
050:
051: private ArrayList<KeywordBean> _results = new ArrayList<KeywordBean>();
052:
053: private int _pTypeSearch = 1;
054:
055: // --------------------------------------------------------------------------------
056: // constructor
057: public KeywordsSearcher(ThesaurusManager tm) {
058: _tm = tm;
059: }
060:
061: // --------------------------------------------------------------------------------
062: public KeywordBean searchById(String id, String sThesaurusName,
063: String lang) throws Exception {
064:
065: _query = "SELECT prefLab, note, id, lowc, uppc "
066: + " FROM {id} rdf:type {skos:Concept}; "
067: + " skos:prefLabel {prefLab};"
068: + " [skos:scopeNote {note} WHERE lang(note) LIKE \""
069: + lang
070: + "\"]; "
071: + " [gml:BoundedBy {} gml:lowerCorner {lowc}]; "
072: + " [gml:BoundedBy {} gml:upperCorner {uppc}] "
073: + " WHERE lang(prefLab) LIKE \""
074: + lang
075: + "\" "
076: + " AND id LIKE \""
077: + id
078: + "\" "
079: + " IGNORE CASE "
080: + " USING NAMESPACE skos=<http://www.w3.org/2004/02/skos/core#>, gml=<http://www.opengis.net/gml#> ";
081:
082: Thesaurus thesaurus = _tm.getThesaurusByName(sThesaurusName);
083:
084: // Perform request
085: QueryResultsTable resultsTable = thesaurus
086: .performRequest(_query);
087: int rowCount = resultsTable.getRowCount();
088: int idKeyword = 0;
089:
090: if (rowCount == 0) {
091: return null;
092: } else {
093: // MUST be one because search by ID
094:
095: // preflab
096: Value value = resultsTable.getValue(0, 0);
097: String sValue = "";
098: if (value != null) {
099: sValue = value.toString();
100: }
101:
102: // uri (= id in RDF file != id in list)
103: Value uri = resultsTable.getValue(0, 2);
104: String sUri = "";
105: if (uri != null) {
106: sUri = uri.toString();
107: }
108:
109: KeywordBean kb = new KeywordBean(idKeyword, sValue, "",
110: sUri, "", "", "", "", sThesaurusName, false, _lang);
111: idKeyword++;
112:
113: return kb;
114: }
115:
116: }
117:
118: public void search(ServiceContext srvContext, Element params)
119: throws Exception {
120: // Get params from request and set default
121: String sKeyword = Util.getParam(params, "pKeyword");
122:
123: // Type of search
124: int pTypeSearch = _pTypeSearch;
125: if (params.getChild("pTypeSearch") != null) { // if param pTypeSearch not here
126: pTypeSearch = Util.getParamAsInt(params, "pTypeSearch");
127:
128: // Thesaurus to search in
129: List listThesauri = new Vector<Element>();
130: // Type of thesaurus to search in
131: String pTypeThesaurus = null;
132: if (params.getChild("pType") != null) // if param pTypeSearch not here
133: pTypeThesaurus = Util.getParam(params, "pType");
134:
135: boolean bAll = true;
136:
137: if (params.getChild("pThesauri") != null) { // if param pThesauri not here
138: listThesauri = params.getChildren("pThesauri");
139: bAll = false;
140:
141: if (((Element) listThesauri.get(0)).getTextTrim()
142: .equals("")) // If first element is empty </>
143: bAll = true;
144: }
145:
146: // If no thesaurus search in all.
147: if (bAll) {
148: Hashtable<String, Thesaurus> tt = _tm
149: .getThesauriTable();
150:
151: Enumeration e = tt.keys();
152: boolean add = true;
153: while (e.hasMoreElements()) // Fill the list with all thesauri available
154: {
155: Thesaurus thesaurus = tt.get(e.nextElement());
156: if (pTypeThesaurus != null) {
157: if (!thesaurus.getDname()
158: .equals(pTypeThesaurus)) // Add thesaurus only if type is corresponding with MD type (based on ISO type ie. theme, discipline, ...)
159: add = false;
160: else
161: add = true;
162: }
163:
164: if (add) {
165: Element el = new Element("pThesauri");
166: el.addContent(thesaurus.getKey());
167: listThesauri.add(el);
168: }
169: }
170: }
171:
172: // Keyword to look for
173: if (!sKeyword.equals("")) {
174:
175: // FIXME : Where to search ? only on term having GUI language or in all ?
176: // Should be
177: // - look for a term in all language
178: // - get prefLab in GUI lang
179: // This will cause multilingual metadata search quite complex !!
180: // Quid Lucene and thesaurus ?
181:
182: String _lang = srvContext.getLanguage();
183: _query = "SELECT prefLab, note, id, lowc, uppc "
184: + " FROM {id} rdf:type {skos:Concept}; "
185: + " skos:prefLabel {prefLab};"
186: + " [skos:scopeNote {note} WHERE lang(note) LIKE \""
187: + _lang
188: + "\"]; "
189: + " [gml:BoundedBy {} gml:lowerCorner {lowc}]; "
190: + " [gml:BoundedBy {} gml:upperCorner {uppc}] "
191: + " WHERE lang(prefLab) LIKE \"" + _lang + "\""
192: + " AND prefLab LIKE ";
193:
194: switch (pTypeSearch) {
195: case 0: // Start with
196: _query += "\"" + sKeyword + "*\" ";
197: break;
198: case 1: // contains
199: _query += "\"*" + sKeyword + "*\" ";
200: break;
201: case 2: // exact match
202: _query += "\"" + sKeyword + "\" ";
203: break;
204: default:
205: break;
206: }
207: _query += " IGNORE CASE "
208: + " USING NAMESPACE skos=<http://www.w3.org/2004/02/skos/core#>, gml=<http://www.opengis.net/gml#> ";
209:
210: }
211:
212: // For each thesaurus, search for keywords in _results
213: _results = new ArrayList<KeywordBean>();
214: int idKeyword = 0;
215:
216: for (int i = 0; i < listThesauri.size(); i++) { // Search in all Thesaurus if none selected
217: Element el = (Element) listThesauri.get(i);
218: String sThesaurusName = el.getTextTrim();
219:
220: Thesaurus thesaurus = _tm
221: .getThesaurusByName(sThesaurusName);
222:
223: // Perform request
224: QueryResultsTable resultsTable = thesaurus
225: .performRequest(_query);
226:
227: int rowCount = resultsTable.getRowCount();
228:
229: for (int row = 0; row < rowCount; row++) {
230: // preflab
231: Value value = resultsTable.getValue(row, 0);
232: String sValue = "";
233: if (value != null) {
234: sValue = value.toString();
235: }
236: // definition
237: Value definition = resultsTable.getValue(row, 1);
238: String sDefinition = "";
239: if (definition != null) {
240: sDefinition = definition.toString();
241: }
242: // uri (= id in RDF file != id in list)
243: Value uri = resultsTable.getValue(row, 2);
244: String sUri = "";
245: if (uri != null) {
246: sUri = uri.toString();
247: }
248:
249: Value lowCorner = resultsTable.getValue(row, 3);
250: Value upperCorner = resultsTable.getValue(row, 4);
251:
252: String sUpperCorner = "";
253: String sLowCorner = "";
254:
255: String sEast = "";
256: String sSouth = "";
257: String sWest = "";
258: String sNorth = "";
259:
260: // lowcorner
261: if (lowCorner != null) {
262: sLowCorner = lowCorner.toString();
263: sWest = sLowCorner.substring(0,
264: sLowCorner.indexOf(' ')).trim();
265: sSouth = sLowCorner.substring(
266: sLowCorner.indexOf(' ')).trim();
267: }
268:
269: // uppercorner
270: if (upperCorner != null) {
271: sUpperCorner = upperCorner.toString();
272: sEast = sUpperCorner.substring(0,
273: sUpperCorner.indexOf(' ')).trim();
274: sNorth = sUpperCorner.substring(
275: sUpperCorner.indexOf(' ')).trim();
276: }
277:
278: KeywordBean kb = new KeywordBean(idKeyword, sValue,
279: sDefinition, sUri, sEast, sWest, sSouth,
280: sNorth, sThesaurusName, false, _lang);
281: _results.add(kb);
282: idKeyword++;
283: }
284: }
285: }
286: }
287:
288: public void searchBN(ServiceContext srvContext, Element params,
289: String request) throws Exception {
290: // TODO : Add geonetinfo elements.
291: String id = Util.getParam(params, "id");
292: String sThesaurusName = Util.getParam(params, "thesaurus");
293:
294: Thesaurus thesaurus = _tm.getThesaurusByName(sThesaurusName);
295:
296: String _lang = srvContext.getLanguage();
297:
298: searchBN(id, sThesaurusName, request, _lang);
299: }
300:
301: public void searchBN(String id, String sThesaurusName,
302: String request, String _lang) throws Exception {
303:
304: Thesaurus thesaurus = _tm.getThesaurusByName(sThesaurusName);
305: _results = new ArrayList<KeywordBean>();
306:
307: String _query = "SELECT prefLab, note, id "
308: + " from {id} rdf:type {skos:Concept};"
309: + " skos:prefLabel {prefLab};"
310: + " [skos:"
311: + request
312: + " {b}];"
313: + " [skos:scopeNote {note} WHERE lang(note) LIKE \""
314: + _lang
315: + "\"] "
316: + " WHERE lang(prefLab) LIKE \""
317: + _lang
318: + "\""
319: + " AND b LIKE \"*"
320: + id
321: + "\""
322: + " IGNORE CASE "
323: + " USING NAMESPACE skos=<http://www.w3.org/2004/02/skos/core#>, gml=<http://www.opengis.net/gml#> ";
324:
325: // Perform request
326: QueryResultsTable resultsTable = thesaurus
327: .performRequest(_query);
328:
329: int rowCount = resultsTable.getRowCount();
330: int idKeyword = 0;
331:
332: for (int row = 0; row < rowCount; row++) {
333:
334: // preflab
335: Value value = resultsTable.getValue(row, 0);
336: String sValue = "";
337: if (value != null) {
338: sValue = value.toString();
339: }
340:
341: // uri (= id in RDF file != id in list)
342: Value uri = resultsTable.getValue(row, 2);
343: String sUri = "";
344: if (uri != null) {
345: sUri = uri.toString();
346: }
347:
348: KeywordBean kb = new KeywordBean(idKeyword, sValue, "",
349: sUri, "", "", "", "", sThesaurusName, false, _lang);
350: _results.add(kb);
351: idKeyword++;
352: }
353: }
354:
355: public void findEnclosedGeoKeyword(String sKeywordCode) {
356: _query = "SELECT prefLab, note, id, lowc, uppc "
357: + " FROM {id} rdf:type {skos:Concept}; "
358: + " skos:prefLabel {prefLab};"
359: + " [skos:scopeNote {note} WHERE lang(note) LIKE \""
360: + _lang
361: + "\"]; "
362: + " [gml:BoundedBy {} gml:lowerCorner {lowc}]; "
363: + " [gml:BoundedBy {} gml:upperCorner {uppc}] "
364: + " WHERE lang(prefLab) LIKE \""
365: + _lang
366: + "\""
367: + " AND prefLab LIKE \""
368: + sKeywordCode
369: + "*\" "
370: + " USING NAMESPACE skos=<http://www.w3.org/2004/02/skos/core#>, gml=<http://www.opengis.net/gml#> ";
371: }
372:
373: public int getNbResults() {
374: return _results.size();
375: }
376:
377: public void sortResults(String tri) {
378: _sortBy = tri;
379: if ("label".equals(tri)) {
380: // sort by label
381: Collections.sort((List) _results, new Comparator() {
382: public int compare(final Object o1, final Object o2) {
383: final KeywordBean kw1 = (KeywordBean) o1;
384: final KeywordBean kw2 = (KeywordBean) o2;
385: return kw1.getValue().compareToIgnoreCase(
386: kw2.getValue());
387: }
388: });
389: }
390: if ("definition".equals(tri)) {
391: // sort by def
392: Collections.sort((List) _results, new Comparator() {
393: public int compare(final Object o1, final Object o2) {
394: final KeywordBean kw1 = (KeywordBean) o1;
395: final KeywordBean kw2 = (KeywordBean) o2;
396: return kw1.getDefinition().compareToIgnoreCase(
397: kw2.getDefinition());
398: }
399: });
400: }
401: }
402:
403: public Element getResults(Element params) throws Exception {
404:
405: Element elDescKeys = new Element("descKeys");
406:
407: // Return only the n first elements according to GUI.
408: int nbResults = 36000;
409: // FIXME
410: if (params.getChild("nbResults") != null)
411: nbResults = Util.getParam(params, "nbResults", this
412: .getNbResults());
413:
414: nbResults = (this .getNbResults() <= nbResults ? this
415: .getNbResults() : nbResults);
416:
417: //for (int i = from; i <= to; i++) {
418: for (int i = 0; i <= nbResults - 1; i++) {
419: KeywordBean kb = (KeywordBean) _results.get(i);
420: Element elKeyword = new Element("keyword");
421: Element elSelected = new Element("selected");
422: // TODO : Add Thesaurus name
423:
424: if (kb.isSelected()) {
425: elSelected.addContent("true");
426: } else {
427: elSelected.addContent("false");
428: }
429: Element elId = new Element("id");
430: elId.addContent(Integer.toString(kb.getId()));
431: Element elValue = new Element("value");
432: elValue.addContent(kb.getValue());
433: Element elDefiniton = new Element("definition");
434: elDefiniton.addContent(kb.getDefinition());
435: Element elUri = new Element("uri");
436: elUri.addContent(kb.getCode());
437: elKeyword.addContent(elSelected);
438: elKeyword.addContent(elId);
439: elKeyword.addContent(elValue);
440: elKeyword.addContent(elDefiniton);
441: elKeyword.addContent(elUri);
442: elDescKeys.addContent(elKeyword);
443: }
444:
445: return elDescKeys;
446: }
447:
448: public void selectUnselectKeywords(Element params) {
449: List listIdKeywordsSelected = params.getChildren("pIdKeyword");
450: for (int i = 0; i < listIdKeywordsSelected.size(); i++) {
451: Element el = (Element) listIdKeywordsSelected.get(i);
452: int keywordId = Integer.decode(el.getTextTrim());
453: for (int j = 0; j < _results.size(); j++) {
454: if (((KeywordBean) _results.get(j)).getId() == keywordId) {
455: ((KeywordBean) _results.get(j))
456: .setSelected(!((KeywordBean) _results
457: .get(j)).isSelected());
458: }
459: }
460: }
461: }
462:
463: /**
464: * @return an element describing the list of selected keywords
465: */
466: public Element getSelectedKeywords() {
467: Element elDescKeys = new Element("descKeys");
468: int nbSelectedKeywords = 0;
469: for (int i = 0; i < this .getNbResults(); i++) {
470: KeywordBean kb = (KeywordBean) _results.get(i);
471: if (kb.isSelected()) {
472: Element elKeyword = new Element("keyword");
473: // keyword type
474: String thesaurusType = kb.getThesaurus();
475: thesaurusType = thesaurusType.replace('.', '-');
476: thesaurusType = thesaurusType.split("-")[1];
477: elKeyword.setAttribute("type", thesaurusType);
478: Element elValue = new Element("value");
479: elValue.addContent(kb.getValue());
480: Element elCode = new Element("code");
481: String code = kb.getRelativeCode();
482: //code = code.split("#")[1];
483: elCode.addContent(code);
484: if (kb.getCoordEast() != null
485: && kb.getCoordWest() != null
486: && kb.getCoordSouth() != null
487: && kb.getCoordNorth() != null) {
488: Element elBbox = new Element("geo");
489: Element elEast = new Element("east");
490: elEast.addContent(kb.getCoordEast());
491: Element elWest = new Element("west");
492: elWest.addContent(kb.getCoordWest());
493: Element elSouth = new Element("south");
494: elSouth.addContent(kb.getCoordSouth());
495: Element elNorth = new Element("north");
496: elNorth.addContent(kb.getCoordNorth());
497: elBbox.addContent(elEast);
498: elBbox.addContent(elWest);
499: elBbox.addContent(elSouth);
500: elBbox.addContent(elNorth);
501: elKeyword.addContent(elBbox);
502: }
503: elKeyword.addContent(elCode);
504: elKeyword.addContent(elValue);
505: elDescKeys.addContent(elKeyword);
506: nbSelectedKeywords++;
507: }
508: }
509: Element elNbTot = new Element("nbtot");
510: elNbTot.addContent(Integer.toString(nbSelectedKeywords));
511: elDescKeys.addContent(elNbTot);
512:
513: return elDescKeys;
514: }
515:
516: /**
517: * @return a collection of descKeys element describing the list of selected keywords
518: */
519: public ArrayList getSelectedKeywordsInDescKeys() {
520: ArrayList listSelectedKeywords = new ArrayList();
521: ArrayList listElDescKeys = new ArrayList();
522:
523: // Get all selected keywords
524: for (int i = 0; i < this .getNbResults(); i++) {
525: KeywordBean kb = (KeywordBean) _results.get(i);
526: if (kb.isSelected()) {
527: listSelectedKeywords.add(kb);
528: }
529: }
530:
531: // Sort keywords
532: Collections.sort((List) listSelectedKeywords, new Comparator() {
533: // Compare
534: public int compare(final Object o1, final Object o2) {
535: final KeywordBean kw1 = (KeywordBean) o1;
536: final KeywordBean kw2 = (KeywordBean) o2;
537: return kw1.getThesaurus().compareToIgnoreCase(
538: kw2.getThesaurus());
539: }
540: });
541:
542: String thesaurusName = "";
543: Element elDescKeys = null;
544: Element elKeyTyp = null;
545: Element elKeyTypCd = null;
546: Element elThesaName = null;
547: Element elResTitle = null;
548: Element elResRefDate = null;
549: Element elRefDate = null;
550: Element elRefDateType = null;
551: Element elDateTypCd = null;
552:
553: for (int i = 0; i < listSelectedKeywords.size(); i++) {
554: KeywordBean kb = (KeywordBean) listSelectedKeywords.get(i);
555: if (!thesaurusName.equals(kb.getThesaurus())) {
556: if (elDescKeys != null) {
557: elKeyTyp.addContent(elKeyTypCd);
558: elDescKeys.addContent(elKeyTyp);
559: elRefDateType.addContent(elDateTypCd);
560: elResRefDate.addContent(elRefDateType);
561: elResRefDate.addContent(elRefDate);
562: elThesaName.addContent(elResTitle);
563: elThesaName.addContent(elResRefDate);
564: elDescKeys.addContent(elThesaName);
565: listElDescKeys.add(elDescKeys.clone());
566: }
567: elDescKeys = new Element("descKeys");
568: String thesaurusType = kb.getThesaurus();
569: thesaurusType = thesaurusType.replace('.', '-');
570: thesaurusType = thesaurusType.split("-")[1];
571: elKeyTyp = new Element("keyTyp");
572: elKeyTypCd = new Element("KeyTypCd");
573: elKeyTypCd.setAttribute("value", thesaurusType);
574: elThesaName = new Element("thesaName");
575: elResTitle = new Element("resTitle");
576: elResTitle.addContent(kb.getThesaurus());
577: elResRefDate = new Element("resRefDate");
578: elRefDate = new Element("refDate");
579: elRefDateType = new Element("refDateType");
580: elDateTypCd = new Element("DateTypCd");
581: elDateTypCd.setAttribute("value", "nill");
582:
583: thesaurusName = kb.getThesaurus();
584: }
585: Element elKeyword = new Element("keyword");
586: elKeyword.addContent(kb.getValue());
587: elDescKeys.addContent(elKeyword);
588: }
589: // add last item
590: if (elDescKeys != null) {
591: elKeyTyp.addContent(elKeyTypCd);
592: elDescKeys.addContent(elKeyTyp);
593: elRefDateType.addContent(elDateTypCd);
594: elResRefDate.addContent(elRefDateType);
595: elResRefDate.addContent(elRefDate);
596: elThesaName.addContent(elResTitle);
597: elThesaName.addContent(elResRefDate);
598: elDescKeys.addContent(elThesaName);
599: listElDescKeys.add(elDescKeys.clone());
600: }
601: return listElDescKeys;
602: }
603:
604: public List getSelectedKeywordsInList() {
605: ArrayList keywords = new ArrayList<KeywordBean>();
606: for (int i = 0; i < this .getNbResults(); i++) {
607: KeywordBean kb = (KeywordBean) _results.get(i);
608: if (kb.isSelected()) {
609: keywords.add(kb);
610: }
611: }
612: return keywords;
613: }
614:
615: public KeywordBean existsResult(String id) {
616: KeywordBean keyword = null;
617: for (int i = 0; i < this .getNbResults(); i++) {
618: KeywordBean kb = (KeywordBean) _results.get(i);
619: if (kb.getId() == Integer.parseInt(id)) {
620: keyword = kb;
621: break;
622: }
623: }
624: return keyword;
625: }
626:
627: }
|