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

Revision 25244, 14.8 KB (checked in by ak19, 8 years ago)

GS3 tomcat server crashes because java crashes owing to some error in the JNI code. The error may be related to pointers having been stored as int rather than long, an issue that's become noticeable on 64 bit linux machines. Changes have been made in the JNI code where these pointers that are transferred between Java and C++ code are stored (GetIntField? and SetIntField? to GetLongField? and SetLongField?, as well as declaration of data_ptr as jlong not jint). Committing code first without debug statements so the commits can easily be done separately.

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#include "org_greenstone_mgpp_MGPPSearchWrapper.h"
34#include "MGPPSearchWrapperImpl.h"
35#include "GSDLQueryParser.h"
36#include "MGQuery.h"
37 
38MGPPSearchData::MGPPSearchData() {
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
64MGPPSearchData::~MGPPSearchData() {
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
78jfieldID FID_mgpp_data = NULL; // MGPPSearchData
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
158/* the java side MGPPSearchWrapper has a pointer to a C++ object - MGPPSearchData
159   initialise this and set the pointer
160*/
161JNIEXPORT jboolean JNICALL
162Java_org_greenstone_mgpp_MGPPSearchWrapper_initCppSide (JNIEnv *j_env, jobject j_obj){
163
164  MGPPSearchData * data = new MGPPSearchData();
165  j_env->SetLongField(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  jlong data_ptr = j_env->GetLongField(j_obj, FID_mgpp_data);
181  MGPPSearchData * data = (MGPPSearchData *)data_ptr;
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  jlong data_ptr = j_env->GetLongField(j_obj, FID_mgpp_data);
213  MGPPSearchData * data = (MGPPSearchData *)data_ptr;
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
236  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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);
247  exc = j_env->ExceptionOccurred(); // this catches the exception I think - it
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);
263    cerr << "MGPPSearchWrapperImpl: invalid query syntax!!\n";
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) {
337  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
350  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
363  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
376  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
384  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
392  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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) {
401  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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 
411  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
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
431  jlong data_ptr = j_env->GetLongField(j_obj, FID_mgpp_data);
432  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(j_obj, FID_mgpp_data);
433
434
435  const char * level = j_env->GetStringUTFChars(j_level, NULL);
436  if (level==NULL) {
437    return; // exception already thrown
438  }
439 
440  data->level.clear();
441  SetCStr(data->level, level);
442 
443  // release the java stuff
444  j_env->ReleaseStringUTFChars(j_level, level);
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  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(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  MGPPSearchData * data = (MGPPSearchData *)j_env->GetLongField(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 browser.