source: gsdl/trunk/trunk/mgpp/jni/MGPPSearchWrapperImpl.cpp@ 16583

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

Undoing change commited in r16582

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