001: //=============================================================================
002: //=== Copyright (C) 2001-2007 Food and Agriculture Organization of the
003: //=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
004: //=== and United Nations Environment Programme (UNEP)
005: //===
006: //=== This program is free software; you can redistribute it and/or modify
007: //=== it under the terms of the GNU General Public License as published by
008: //=== the Free Software Foundation; either version 2 of the License, or (at
009: //=== your option) any later version.
010: //===
011: //=== This program is distributed in the hope that it will be useful, but
012: //=== WITHOUT ANY WARRANTY; without even the implied warranty of
013: //=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: //=== General Public License for more details.
015: //===
016: //=== You should have received a copy of the GNU General Public License
017: //=== along with this program; if not, write to the Free Software
018: //=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
019: //===
020: //=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
021: //=== Rome - Italy. email: geonetwork@osgeo.org
022: //==============================================================================
023:
024: package org.fao.geonet.services.util.z3950;
025:
026: import com.k_int.IR.AsynchronousEnumeration;
027: import com.k_int.IR.DefaultSourceEnumeration;
028: import com.k_int.IR.IFSNotificationTarget;
029: import com.k_int.IR.IREvent;
030: import com.k_int.IR.IRQuery;
031: import com.k_int.IR.IRStatusReport;
032: import com.k_int.IR.InformationFragment;
033: import com.k_int.IR.InformationFragmentSource;
034: import com.k_int.IR.InvalidQueryException;
035: import com.k_int.IR.QueryModel;
036: import com.k_int.IR.RecordFormatSpecification;
037: import com.k_int.IR.SearchTask;
038: import com.k_int.IR.Syntaxes.DOMTree;
039: import com.k_int.util.RPNQueryRep.AttrPlusTermNode;
040: import com.k_int.util.RPNQueryRep.AttrTriple;
041: import com.k_int.util.RPNQueryRep.ComplexNode;
042: import com.k_int.util.RPNQueryRep.QueryNode;
043: import com.k_int.util.RPNQueryRep.QueryNodeVisitor;
044: import com.k_int.util.RPNQueryRep.RootNode;
045: import java.util.Enumeration;
046: import java.util.List;
047: import java.util.Observer;
048: import java.util.Properties;
049: import java.util.Stack;
050: import jeeves.server.ServiceConfig;
051: import jeeves.server.context.ServiceContext;
052: import jeeves.utils.Log;
053: import jeeves.utils.Xml;
054: import org.fao.geonet.GeonetContext;
055: import org.fao.geonet.constants.Edit;
056: import org.fao.geonet.constants.Geonet;
057: import org.fao.geonet.kernel.search.MetaSearcher;
058: import org.fao.geonet.kernel.search.SearchManager;
059: import org.jdom.Attribute;
060: import org.jdom.Document;
061: import org.jdom.Element;
062: import org.jdom.output.DOMOutputter;
063:
064: //=============================================================================
065:
066: public class GNSearchTask extends SearchTask implements
067: InformationFragmentSource {
068: private static final String[] PRIVATE_STATUS_TYPES = { "Idle",
069: "Searching", "Search complete", "Requesting records",
070: "All records returned" };
071:
072: public int _demoSearchStatus = 0;
073:
074: private int _fragmentCount = 0;
075: private IRQuery _query = null;
076: private GNSearchable _source = null;
077: private ServiceContext _srvContext;
078: private Properties _properties;
079:
080: private MetaSearcher _searcher;
081:
082: //--------------------------------------------------------------------------
083:
084: public GNSearchTask(IRQuery query, GNSearchable source,
085: Observer[] observers, Properties properties,
086: ServiceContext srvContext) {
087: super (observers);
088: Log.debug(Geonet.Z3950_SERVER, "Creating search task");
089:
090: _query = query;
091: _source = source;
092: _srvContext = srvContext;
093: _properties = properties;
094: setTaskStatusCode(TASK_IDLE);
095: Log.debug(Geonet.Z3950_SERVER, "Search task created");
096: }
097:
098: //--------------------------------------------------------------------------
099:
100: public void destroy() {
101: // TODO: check if empty method is correct
102: }
103:
104: //--------------------------------------------------------------------------
105:
106: /* TODO: not used, remove
107: / * * from SearchTask abstract base class * /
108: public void destroyTask()
109: {
110: super.destroyTask();
111: }
112: */
113:
114: //--------------------------------------------------------------------------
115: public int getPrivateTaskStatusCode() {
116: return _demoSearchStatus;
117: }
118:
119: //--------------------------------------------------------------------------
120:
121: public void setPrivateTaskStatusCode(int i) {
122: _demoSearchStatus = i;
123: }
124:
125: //--------------------------------------------------------------------------
126:
127: public String lookupPrivateStatusCode(int code) {
128: return PRIVATE_STATUS_TYPES[code];
129: }
130:
131: //--------------------------------------------------------------------------
132:
133: public int evaluate(int timeout) {
134: try {
135: Log.debug(Geonet.Z3950_SERVER, "INCOMING QUERY:\n"
136: + _query.getQueryModel());
137:
138: RemoteQueryDecoder queryDecoder = new RemoteQueryDecoder(
139: _query.getQueryModel());
140: Element request = new Element("request");
141:
142: Log.debug(Geonet.Z3950_SERVER, "INCOMING XML QUERY:\n"
143: + Xml.getString(queryDecoder.getQuery()));
144:
145: request.addContent(queryDecoder.getQuery());
146: ServiceConfig config = new ServiceConfig();
147:
148: // possibly close old searcher
149: if (_searcher != null)
150: _searcher.close();
151:
152: // perform the search and save search results
153: GeonetContext gc = (GeonetContext) _srvContext
154: .getHandlerContext(Geonet.CONTEXT_NAME);
155: SearchManager searchMan = gc.getSearchmanager();
156:
157: MetaSearcher s = searchMan.newSearcher(
158: SearchManager.LUCENE,
159: Geonet.File.SEARCH_Z3950_SERVER);
160: s.search(_srvContext, request, config);
161: _searcher = s;
162:
163: // System.out.println("summary:\n" + Xml.getString(s.getSummary())); // DEBUG
164:
165: // Random number of records.. Set up the result set
166: setFragmentCount(s.getSize());
167: setTaskStatusCode(TASK_COMPLETE);
168:
169: _srvContext.getResourceManager().close();
170: } catch (Throwable e) {
171: e.printStackTrace();
172:
173: try {
174: _srvContext.getResourceManager().abort();
175: } catch (Exception e2) {
176: e2.printStackTrace();
177: }
178: }
179: return (getTaskStatusCode());
180: }
181:
182: //--------------------------------------------------------------------------
183:
184: public InformationFragment[] getFragment(int startingFragment,
185: int count, RecordFormatSpecification spec) {
186: Log.debug(Geonet.Z3950_SERVER, "Request for fragment start:"
187: + startingFragment + ", count:" + count);
188:
189: InformationFragment fragment[] = new InformationFragment[count];
190: try {
191: // build fragment data
192: int from = startingFragment;
193: int to = startingFragment + count - 1;
194:
195: Element request = new Element("request");
196: request.addContent(new Element("from").setText(from + ""));
197: request.addContent(new Element("to").setText(to + ""));
198: ServiceConfig config = new ServiceConfig();
199:
200: Log.debug(Geonet.Z3950_SERVER, "Search request:\n"
201: + Xml.getString(request));
202: // get result set
203: Element result = _searcher.present(_srvContext, request,
204: config);
205:
206: Log.debug(Geonet.Z3950_SERVER, "Search result:\n"
207: + Xml.getString(result));
208:
209: // remove summary
210: result.removeChildren("summary");
211: List list = result.getChildren();
212:
213: Log.debug(Geonet.Z3950_SERVER, "Set name asked:"
214: + spec.getSetname());
215:
216: // save other records to fragment
217: for (int i = 0; i < count; i++) {
218: Element md = (Element) list.get(0);
219: md.detach();
220:
221: Log.debug(Geonet.Z3950_SERVER, "Returning fragment:\n"
222: + Xml.getString(md));
223:
224: // add metadata
225: fragment[i] = new DOMTree("geonetwork", "geonetwork",
226: null, getRecord(md),
227: new RecordFormatSpecification("xml", "meta",
228: "f"));
229: }
230: _srvContext.getResourceManager().close();
231: Log.debug(Geonet.Z3950_SERVER, "Fragment returned");
232: } catch (Throwable e) {
233: try {
234: _srvContext.getResourceManager().abort();
235: } catch (Exception e2) {
236: e2.printStackTrace();
237: }
238:
239: e.printStackTrace();
240: }
241: return fragment;
242: }
243:
244: //--------------------------------------------------------------------------
245:
246: private org.w3c.dom.Document getRecord(Element metadata)
247: throws Exception {
248: DOMOutputter outputter = new DOMOutputter();
249: return outputter.output(new Document(metadata));
250: }
251:
252: //--------------------------------------------------------------------------
253:
254: public void asyncGetFragment(int startingFragment, int count,
255: RecordFormatSpecification spec, IFSNotificationTarget target) {
256: }
257:
258: //--------------------------------------------------------------------------
259:
260: public void store(int id, InformationFragment fragment) {
261: }
262:
263: //--------------------------------------------------------------------------
264:
265: public void setFragmentCount(int i) {
266: _fragmentCount = i;
267: IREvent e = new IREvent(IREvent.FRAGMENT_COUNT_CHANGE,
268: new Integer(i));
269: setChanged();
270: notifyObservers(e);
271: }
272:
273: //--------------------------------------------------------------------------
274:
275: public int getFragmentCount() {
276: return _fragmentCount;
277: }
278:
279: //--------------------------------------------------------------------------
280:
281: public InformationFragmentSource getTaskResultSet() {
282: return this ;
283: }
284:
285: //--------------------------------------------------------------------------
286:
287: public AsynchronousEnumeration elements() {
288: return new DefaultSourceEnumeration(this );
289: }
290:
291: //--------------------------------------------------------------------------
292:
293: public IRStatusReport getStatusReport() {
294: return new IRStatusReport("Demo", "Demo", "Demo",
295: PRIVATE_STATUS_TYPES[_demoSearchStatus],
296: getFragmentCount(), getFragmentCount(), null,
297: getLastStatusMessages());
298: }
299: }
300:
301: //--------------------------------------------------------------------------
302: // converts an RPN query to xml
303: class RemoteQueryDecoder {
304: private Stack stack = new Stack();
305: private String attrSet;
306:
307: public RemoteQueryDecoder(QueryModel qm) {
308: try {
309: RootNode rn = qm.toRPN();
310: QueryNodeVisitor qnv = new QueryNodeVisitor() {
311: public void visit(AttrPlusTermNode aptn) {
312: super .visit(aptn);
313: Element node = new Element("term");
314: for (Enumeration enu = aptn.getAttrEnum(); enu
315: .hasMoreElements();) {
316: AttrTriple triple = (AttrTriple) enu
317: .nextElement();
318: int type = triple.getAttrType().intValue();
319: String value = triple.getAttrVal().toString();
320: node
321: .setAttribute(getAttrAttribute(type,
322: value));
323: }
324: node.addContent(aptn.getTermAsString(false));
325: stack.push(node);
326: }
327:
328: public void visit(ComplexNode cn) {
329: super .visit(cn);
330: Element rightChild = (Element) stack.pop();
331: Element leftChild = (Element) stack.pop();
332: Element node = new Element(getOpString(cn.getOp()));
333: node.addContent(leftChild);
334: node.addContent(rightChild);
335: stack.push(node);
336: }
337:
338: public void visit(QueryNode qn) {
339: super .visit(qn);
340: }
341:
342: public void visit(RootNode rn) {
343: super .visit(rn);
344: Element query = new Element("query");
345: query.setAttribute("attrset", rn.getAttrset());
346: query.addContent((Element) stack.pop());
347: stack.push(query);
348: }
349: };
350: qnv.visit(rn);
351: } catch (InvalidQueryException iqe) {
352: iqe.printStackTrace();
353: }
354: }
355:
356: public Element getQuery() {
357: return (Element) stack.peek();
358: }
359:
360: public String getAttrSet() {
361: return attrSet;
362: }
363:
364: public String toString() {
365: return Xml.getString(getQuery());
366: }
367:
368: private String getOpString(int op) {
369: switch (op) {
370: case ComplexNode.COMPLEX_AND:
371: return "and";
372: case ComplexNode.COMPLEX_ANDNOT:
373: return "not";
374: case ComplexNode.COMPLEX_OR:
375: return "or";
376: case ComplexNode.COMPLEX_PROX:
377: return "prox";
378: default:
379: return op + "";
380: }
381: }
382:
383: private Attribute getAttrAttribute(int attrType, String attrValue) {
384: switch (attrType) {
385: case 1:
386: return new Attribute("use", attrValue);
387: case 2:
388: return new Attribute("relation", attrValue);
389: case 4:
390: return new Attribute("structure", attrValue);
391: case 5:
392: return new Attribute("truncation", attrValue);
393: default:
394: return new Attribute(attrType + "", attrValue);
395: }
396: }
397: }
|