source: indexers/trunk/mgpp/jni/MGPPSearchWrapperImpl.cpp@ 14910

Last change on this file since 14910 was 14910, checked in by davidb, 16 years ago

Standardisation of Windows config file to lowercase (included from this source file). Was causing a problem when trying to compile on Unix filesystem mounted under Windows.

File size: 14.8 KB
Line 
1/*
2 * MGPPSearchWrapperImpl.c
3 * Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19#ifdef __WIN32__
20#include <win32cfg.h>
21#include <strstream>
22#include <sstream>
23#else
24#ifdef __APPLE__
25#include <strstream>
26#include <sstream>
27#else
28#include <sstream>
29#endif
30#endif
31
32#include <jni.h>
33#include "org_greenstone_mgpp_MGPPSearchWrapper.h"
34#include "MGPPWrapperImpl.h"
35#include "TextGet.h"
36#include "GSDLQueryParser.h"
37#include "MGQuery.h"
38
39MGPPWrapperData::MGPPWrapperData() {
40 indexData = new IndexData();
41 queryInfo = new QueryInfo();
42
43 if (queryInfo==NULL) {
44 cerr<<"couldn't allocate new query info\n";
45 if (indexData!=NULL) {
46 delete indexData;
47 }
48 }
49
50 // set all the default params
51 SetCStr(queryInfo->docLevel, "Document"); // the level to search at
52 queryInfo->maxDocs = 50;
53 queryInfo->sortByRank = true;
54 queryInfo->exactWeights = false;
55 queryInfo->needRankInfo = true;
56 queryInfo->needTermFreqs = true;
57
58 UCArrayClear(level);
59 SetCStr(level, "Document"); // the level to return docs at
60 defaultStemMethod=0;
61 defaultBoolCombine=0;
62 maxNumeric = 4;
63}
64
65MGPPWrapperData::~MGPPWrapperData() {
66 if (indexData !=NULL) {
67 delete indexData;
68 }
69 if (queryInfo !=NULL) {
70 delete queryInfo;
71 }
72}
73
74// ********************************************
75// initialisation stuff
76// ********************************************
77
78// cached ids for java stuff
79jfieldID FID_mgpp_data = NULL; // MGPPWrapperData
80jfieldID FID_query_result = NULL; // MGPPQueryResult
81jmethodID MID_addDoc=NULL; // MGPPQueryResult.addDoc()
82jmethodID MID_addTerm=NULL; // MGPPQueryResult.addTerm()
83jmethodID MID_setTotalDocs=NULL; // MGPPQueryResult.setTotalDocs()
84jmethodID MID_clearResult=NULL; //MGPPQueryResult.clear()
85jmethodID MID_setSyntaxError=NULL; // MGPPQueryResult.setSyntaxError()
86jclass CID_String=NULL; // class ID of String
87
88/* to access objects and methods on java side, need their field/method ids -
89 this initialises them at the start to avoid recalculating them each time they
90 are needed
91Note: the descriptors need to be exactly right, otherwise you get an error
92saying "no such field" but no reference to the fact that it has the right
93name but the wrong type.
94Note: apparently the jclass is a local ref and should only work
95in the method that created it. It seems to work ok, but I'll make it
96 global cos the book said I should, and it may avoid future hassles.
97*/
98JNIEXPORT void JNICALL
99Java_org_greenstone_mgpp_MGPPSearchWrapper_initIDs (JNIEnv *j_env, jclass j_cls) {
100
101 FID_mgpp_data = j_env->GetFieldID(j_cls, "mgpp_data_ptr_", "J"); //a long-"J"
102 if (FID_mgpp_data==NULL) {
103 cerr <<"MGPP JNI: field mgpp_data_ptr_ not found"<<endl;
104 }
105
106 FID_query_result = j_env->GetFieldID(j_cls, "mgpp_query_result_", "Lorg/greenstone/mgpp/MGPPQueryResult;"); // an object -"L<class name>;"
107 if (FID_query_result==NULL) {
108 cerr <<"MGPP JNI: field mgpp_query_result_ not found"<<endl;
109 }
110 // the methods we want to use
111
112 // addDoc(long doc, float rank)
113 jclass JC_MGPPQueryResult = j_env->FindClass("org/greenstone/mgpp/MGPPQueryResult");
114 MID_addDoc = j_env->GetMethodID(JC_MGPPQueryResult, "addDoc", "(JF)V");
115 if (MID_addDoc==NULL) {
116 cerr <<"MGPP JNI: addDoc method not found"<<endl;
117 }
118 // addTerm(String term, String tag, int stem_method, long match_docs,
119 // long term_freq, String[] equiv_terms)
120 MID_addTerm = j_env->GetMethodID(JC_MGPPQueryResult, "addTerm", "(Ljava/lang/String;Ljava/lang/String;IJJ[Ljava/lang/String;)V");
121 if (MID_addTerm==NULL) {
122 cerr <<"MGPP JNI: method addTerm not found"<<endl;
123 }
124
125 // setTotalDocs(long)
126 MID_setTotalDocs = j_env->GetMethodID(JC_MGPPQueryResult, "setTotalDocs", "(J)V");
127 if (MID_setTotalDocs==NULL) {
128 cerr <<"MGPP JNI: method setTotalDocs not found"<<endl;
129 }
130
131 MID_clearResult = j_env->GetMethodID(JC_MGPPQueryResult, "clear", "()V");
132 if (MID_clearResult==NULL) {
133 cerr <<"MGPP JNI: method clear not found"<<endl;
134 }
135 MID_setSyntaxError = j_env->GetMethodID(JC_MGPPQueryResult, "setSyntaxError", "(Z)V");
136 if (MID_clearResult==NULL) {
137 cerr <<"MGPP JNI: method setSyntaxError not found"<<endl;
138 }
139
140 // get the class for String to use in NewObjectArray in runQuery()
141 // FindClass returns a local reference - have to convert it to a global one
142 jclass local_CID_String = j_env->FindClass("java/lang/String");
143 if (local_CID_String==NULL) {
144 cerr <<"MGPP JNI: java String class not found"<<endl;
145 } else {
146 /* create a global ref */
147 CID_String = (jclass)j_env->NewGlobalRef(local_CID_String);
148 /* The local reference is no longer useful */
149 j_env->DeleteLocalRef(local_CID_String);
150
151 /* Is the global reference created successfully? */
152 if (CID_String == NULL) {
153 return; /* out of memory exception thrown */
154 }
155 }
156
157}
158
159/* the java side MGPPWrapper has a pointer to a C++ object - MGPPWrapperData
160 initialise this and set the pointer
161*/
162JNIEXPORT jboolean JNICALL
163Java_org_greenstone_mgpp_MGPPSearchWrapper_initCppSide (JNIEnv *j_env, jobject j_obj){
164
165 MGPPWrapperData * data = new MGPPWrapperData();
166 j_env->SetIntField(j_obj, FID_mgpp_data, (long)data);
167
168 return true;
169
170}
171
172//******************************************
173// do a query
174// ****************************************
175
176/* load the IndexData - cached for querying
177 */
178JNIEXPORT jboolean JNICALL
179Java_org_greenstone_mgpp_MGPPSearchWrapper_loadIndexData (JNIEnv *j_env, jobject j_obj, jstring j_index_name) {
180
181 jint data_ptr = j_env->GetIntField(j_obj, FID_mgpp_data);
182 MGPPWrapperData * data = (MGPPWrapperData *)data_ptr;
183
184#ifdef __WIN32__
185 const char* base_dir = "";
186#else
187 const char* base_dir = "/";
188#endif
189
190 const char * index_name = j_env->GetStringUTFChars( j_index_name, NULL);
191 if (index_name==NULL) {
192 return false;
193 }
194
195 jboolean j_result=false;
196
197 // why doesn't this complain about const??
198 if (data->indexData->LoadData(base_dir, index_name)) {
199 j_result=true;
200 }
201
202 // release any gets
203 j_env->ReleaseStringUTFChars(j_index_name, index_name);
204
205 return j_result;
206}
207
208/* unload the data
209 */
210JNIEXPORT jboolean JNICALL
211Java_org_greenstone_mgpp_MGPPSearchWrapper_unloadIndexData (JNIEnv *j_env, jobject j_obj) {
212
213 jint data_ptr = j_env->GetIntField(j_obj, FID_mgpp_data);
214 MGPPWrapperData * data = (MGPPWrapperData *)data_ptr;
215
216 data->indexData->UnloadData();
217 return true;
218
219}
220
221/* do the actual query - the results are written to query_result held on the
222 java side */
223JNIEXPORT void JNICALL
224Java_org_greenstone_mgpp_MGPPSearchWrapper_runQuery (JNIEnv *j_env, jobject j_obj, jstring j_query){
225
226 jthrowable exc; // an exception - check if something funny has happened
227 const char *query = j_env->GetStringUTFChars(j_query, NULL);
228 if (query==NULL) {
229 return; // exception already thrown
230 }
231 // turn to UCArray for mgpp and then release the string
232 UCArray queryArray;
233 SetCStr(queryArray, query);
234 j_env->ReleaseStringUTFChars(j_query, query);
235
236 // the query data
237 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
238
239 // the result to write to
240 jobject result_ptr = j_env->GetObjectField(j_obj, FID_query_result);
241 if (result_ptr==NULL) {
242 cerr <<"couldn't access the result to write to"<<endl;
243 return;
244 }
245
246 // clear the result
247 j_env->CallVoidMethod(result_ptr, MID_clearResult);
248 exc = j_env->ExceptionOccurred(); // this catches teh exception I think - it
249 //wont be thrown any further
250 if (exc) {
251 j_env->ExceptionDescribe();
252 return;
253 }
254 // the mgpp QueryResult that we will use
255 ExtQueryResult queryResult;
256
257 QueryNode * queryTree = NULL;
258 // parse the query string into a tree structure
259 queryTree = ParseQuery(queryArray, data->defaultBoolCombine,
260 data->defaultStemMethod, data->maxNumeric);
261 if (queryTree == NULL) {
262 // invalid syntax
263 j_env->CallVoidMethod(result_ptr, MID_setSyntaxError, true);
264 cerr << "MGPPWrapperImpl: invalid query syntax!!\n";
265 return;
266 }
267 // print the query
268 PrintNode (cout, queryTree);
269 // finally, do the query
270 MGQuery(*(data->indexData), *(data->queryInfo), queryTree, queryResult, data->level);
271
272 delete queryTree;
273
274 // convert queryResult to the java side version
275 // use levels rather than docs of ExtQueryResult
276 // CallVoidMethod(obj, method id, args to method)
277 for (int i=0; i<queryResult.levels.size(); i++) {
278 jlong doc = queryResult.levels[i];
279 jfloat rank = queryResult.ranks[i];
280 j_env->CallVoidMethod(result_ptr, MID_addDoc, doc, rank);
281 exc = j_env->ExceptionOccurred();
282 if (exc) {
283 j_env->ExceptionDescribe();
284 return;
285 }
286
287 }
288
289 // actual num of docs
290 jlong total = queryResult.actualNumDocs;
291 j_env->CallVoidMethod(result_ptr, MID_setTotalDocs, total);
292 exc = j_env->ExceptionOccurred();
293 if (exc) {
294 j_env->ExceptionDescribe();
295 return;
296 }
297
298 // the terms
299 for (int j=0; j<queryResult.termFreqs.size(); j++) {
300
301 TermFreqData tf = queryResult.termFreqs[j];
302 jstring term = j_env->NewStringUTF(GetCStr(tf.term));
303 jstring tag = j_env->NewStringUTF(GetCStr(tf.tag));
304 jint stem = tf.stemMethod;
305 jlong match = tf.matchDocs;
306 jlong freq = tf.termFreq;
307
308 jobjectArray equivs=NULL;
309 jstring empty = j_env->NewStringUTF(""); // the initial object to fill the array
310 jint num_equivs = tf.equivTerms.size();
311 equivs = j_env->NewObjectArray(num_equivs, CID_String, empty);
312 if (equivs==NULL) {
313 cerr<<"couldn't create object array"<<endl;
314
315 } else {
316 for (int k=0; k<num_equivs;k++) {
317 jstring equiv = j_env->NewStringUTF(GetCStr(tf.equivTerms[k]));
318 j_env->SetObjectArrayElement(equivs, k, equiv);
319 }
320
321
322 j_env->CallVoidMethod(result_ptr, MID_addTerm, term, tag, stem, match, freq, equivs);
323 exc = j_env->ExceptionOccurred();
324 if (exc) {
325 j_env->ExceptionDescribe();
326 return;
327 }
328 }
329 }
330
331
332}
333
334JNIEXPORT void JNICALL
335Java_org_greenstone_mgpp_MGPPSearchWrapper_setStem (JNIEnv *j_env,
336 jobject j_obj,
337 jboolean j_on) {
338 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
339 if (j_on) {
340 data->defaultStemMethod |= 2;
341 } else {
342 data->defaultStemMethod &= 0xd;
343 }
344
345}
346
347JNIEXPORT void JNICALL
348Java_org_greenstone_mgpp_MGPPSearchWrapper_setAccentFold (JNIEnv *j_env,
349 jobject j_obj,
350 jboolean j_on) {
351 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
352 if (j_on) {
353 data->defaultStemMethod |= 4;
354 } else {
355 data->defaultStemMethod &= 0xb;
356 }
357}
358
359
360JNIEXPORT void JNICALL
361Java_org_greenstone_mgpp_MGPPSearchWrapper_setCase (JNIEnv *j_env,
362 jobject j_obj,
363 jboolean j_on) {
364 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
365
366 if (j_on) {
367 data->defaultStemMethod |= 1;
368 } else {
369 data->defaultStemMethod &= 0xe;
370 }
371}
372
373JNIEXPORT void JNICALL
374Java_org_greenstone_mgpp_MGPPSearchWrapper_setMaxDocs (JNIEnv *j_env,
375 jobject j_obj,
376 jint j_max) {
377 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
378 data->queryInfo->maxDocs=j_max;
379}
380
381JNIEXPORT void JNICALL
382Java_org_greenstone_mgpp_MGPPSearchWrapper_setMaxNumeric (JNIEnv *j_env,
383 jobject j_obj,
384 jint j_max) {
385 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
386 data->maxNumeric=j_max;
387}
388
389JNIEXPORT void JNICALL
390Java_org_greenstone_mgpp_MGPPSearchWrapper_setSortByRank (JNIEnv *j_env,
391 jobject j_obj,
392 jboolean j_on) {
393 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
394
395 data->queryInfo->sortByRank=j_on;
396}
397
398JNIEXPORT void JNICALL
399Java_org_greenstone_mgpp_MGPPSearchWrapper_setReturnTerms(JNIEnv *j_env,
400 jobject j_obj,
401 jboolean j_on) {
402 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
403 data->queryInfo->needTermFreqs = j_on;
404
405}
406
407JNIEXPORT void JNICALL
408Java_org_greenstone_mgpp_MGPPSearchWrapper_setQueryLevel(JNIEnv *j_env,
409 jobject j_obj,
410 jstring j_level){
411
412 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
413
414 const char * level = j_env->GetStringUTFChars(j_level, NULL);
415 if (level==NULL) {
416 return; // exception already thrown
417 }
418
419 data->queryInfo->docLevel.clear();
420 SetCStr(data->queryInfo->docLevel, level);
421
422 // release the java stuff
423 j_env->ReleaseStringUTFChars(j_level, level);
424
425}
426
427JNIEXPORT void JNICALL
428Java_org_greenstone_mgpp_MGPPSearchWrapper_setReturnLevel(JNIEnv *j_env,
429 jobject j_obj,
430 jstring j_level){
431
432 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
433
434 const char * level = j_env->GetStringUTFChars(j_level, NULL);
435 if (level==NULL) {
436 return; // exception already thrown
437 }
438
439 data->level.clear();
440 SetCStr(data->level, level);
441
442 // release the java stuff
443 j_env->ReleaseStringUTFChars(j_level, level);
444
445
446}
447
448JNIEXPORT void JNICALL
449Java_org_greenstone_mgpp_MGPPSearchWrapper_setMatchMode (JNIEnv *j_env,
450 jobject j_obj,
451 jint j_mode){
452
453 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
454 data->defaultBoolCombine=j_mode;
455
456}
457
458JNIEXPORT jstring JNICALL
459Java_org_greenstone_mgpp_MGPPSearchWrapper_getQueryParams (JNIEnv *j_env,
460 jobject j_obj){
461
462 MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data);
463
464 // print the data to a stringstream, then convert to char*, then to
465 //jstring
466
467 stringstream output;
468 output << "Query params:"<<endl
469 // need to change this to use platform specific separator for niceness
470 << "index\t\t"<<data->indexData->basePath<<"/"<<data->indexData->filename<<endl
471 <<"search level\t"<<GetCStr(data->queryInfo->docLevel)<<endl
472 <<"result level\t"<<GetCStr(data->level)<<endl
473 <<"casefold\t"<<(data->defaultStemMethod&1)<<endl
474 <<"stem\t\t"<<(data->defaultStemMethod&2)<<endl
475 <<"order by rank\t"<<data->queryInfo->sortByRank<<endl
476 <<"query type\t"<<(data->defaultBoolCombine==1?"all":"some")<<endl
477 <<"max docs\t"<<data->queryInfo->maxDocs<<endl<<ends;
478
479 const char *result = output.str().c_str();
480 jstring j_result = j_env->NewStringUTF(result);
481 delete (char *)result;
482 return j_result;
483}
Note: See TracBrowser for help on using the repository browser.