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

Last change on this file since 9778 was 9778, checked in by kjdon, 19 years ago

few changes to get the stringstream bit working on windows

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