source: main/trunk/greenstone2/common-src/indexers/mgpp/jni/MGPPSearchWrapperImpl.cpp@ 26660

Last change on this file since 26660 was 26660, checked in by davidb, 11 years ago

Support for cross-compilation added. This particular set of changes focus on flags that assist cross-compilation with JNI

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