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

Last change on this file since 4212 was 4212, checked in by kjdon, 21 years ago

mgpp parseQuery returns NULL if theres been a syntax error, the jni stuff sets a syntaxError variable in MGPPQueryResult to true. also fixed some stuff left over from teh basedir change in teh cpp code

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