source: trunk/mgpp/jni/MGPPWrapperImpl.cpp@ 3980

Last change on this file since 3980 was 3980, checked in by mdewsnip, 21 years ago

Made changes so that passing the base path as a separate parameter is not required (this is needed under Windows). Needs tidying up.

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