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

Revision 26660, 18.1 KB (checked in by davidb, 7 years ago)

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

Line 
1/*
2 *    MGPPSearchWrapperImpl.cpp
3 *    Copyright (C) 2007 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
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
50#include "org_greenstone_mgpp_MGPPSearchWrapper.h"
51#include "MGPPSearchWrapperImpl.h"
52#include "GSDLQueryParser.h"
53#include "MGQuery.h"
54
55// toggle debugging
56//#define _DEBUG
57 
58MGPPSearchData::MGPPSearchData() {
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
84MGPPSearchData::~MGPPSearchData() {
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
98jfieldID FID_mgpp_data = NULL; // MGPPSearchData
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
178/* the java side MGPPSearchWrapper has a pointer to a C++ object - MGPPSearchData
179   initialise this and set the pointer
180*/
181JNIEXPORT jboolean JNICALL
182Java_org_greenstone_mgpp_MGPPSearchWrapper_initCppSide (JNIEnv *j_env, jobject j_obj){
183
184#ifdef _DEBUG
185  cerr << "**** JNI debugging for GS3. initCppSide: SetLongField()\n";
186#endif
187
188  MGPPSearchData * data = new MGPPSearchData();
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
195  j_env->SetLongField(j_obj, FID_mgpp_data, (long)data);
196
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
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) {
214#ifdef _DEBUG
215  fprintf (stderr, "in loadIndexData\n");
216#endif
217
218  jlong data_ptr = j_env->GetLongField(j_obj, FID_mgpp_data);
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
224  MGPPSearchData * data = (MGPPSearchData *)data_ptr;
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
255#ifdef _DEBUG
256  fprintf (stderr, "in unloadIndexData\n");
257#endif
258
259  jlong data_ptr = j_env->GetLongField(j_obj, FID_mgpp_data);
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
265  MGPPSearchData * data = (MGPPSearchData *)data_ptr;
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
288  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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);
299  exc = j_env->ExceptionOccurred(); // this catches the exception I think - it
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);
315    cerr << "MGPPSearchWrapperImpl: invalid query syntax!!\n";
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) {
389  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
402  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
415  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
428  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
436  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
444  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
453  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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 
463  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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){
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
490
491  jlong data_ptr = j_env->GetLongField(j_obj, FID_mgpp_data);
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
497  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
498
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
503
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
510  const char * level = j_env->GetStringUTFChars(j_level, NULL);
511  if (level==NULL) {
512    return; // exception already thrown
513  }
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
519 
520  data->level.clear();
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
527  SetCStr(data->level, level);
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
533 
534  // release the java stuff
535  j_env->ReleaseStringUTFChars(j_level, level);
536
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
542}
543
544JNIEXPORT void JNICALL
545Java_org_greenstone_mgpp_MGPPSearchWrapper_setMatchMode (JNIEnv *j_env,
546                           jobject j_obj,
547                           jint j_mode){
548
549  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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
558  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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 browser.