#ifdef __WIN32__ #include #include #else #ifdef __APPLE__ #include #include #else #include #include #include #endif #endif #include #include "org_greenstone_mgpp_MGPPWrapper.h" #include "MGPPWrapperImpl.h" #include "TextGet.h" #include "GSDLQueryParser.h" #include "MGQuery.h" MGPPWrapperData::MGPPWrapperData() { indexData = new IndexData(); queryInfo = new QueryInfo(); if (queryInfo==NULL) { cerr<<"couldn't allocate new query info\n"; if (indexData!=NULL) { delete indexData; } } // set all the default params SetCStr(queryInfo->docLevel, "Document"); // the level to search at queryInfo->maxDocs = 50; queryInfo->sortByRank = true; queryInfo->exactWeights = false; queryInfo->needRankInfo = true; queryInfo->needTermFreqs = true; UCArrayClear(level); SetCStr(level, "Document"); // the level to return docs at defaultStemMethod=0; defaultBoolCombine=0; } MGPPWrapperData::~MGPPWrapperData() { if (indexData !=NULL) { delete indexData; } if (queryInfo !=NULL) { delete queryInfo; } } // ******************************************** // initialisation stuff // ******************************************** // cached ids for java stuff jfieldID FID_mgpp_data = NULL; // MGPPWrapperData jfieldID FID_query_result = NULL; // MGPPQueryResult jmethodID MID_addDoc=NULL; // MGPPQueryResult.addDoc() jmethodID MID_addTerm=NULL; // MGPPQueryResult.addTerm() jmethodID MID_setTotalDocs=NULL; // MGPPQueryResult.setTotalDocs() jmethodID MID_clearResult=NULL; //MGPPQueryResult.clear() jmethodID MID_setSyntaxError=NULL; // MGPPQueryResult.setSyntaxError() jclass CID_String=NULL; // class ID of String /* to access objects and methods on java side, need their field/method ids - this initialises them at the start to avoid recalculating them each time they are needed Note: the descriptors need to be exactly right, otherwise you get an error saying "no such field" but no reference to the fact that it has the right name but the wrong type. Note: apparently the jclass is a local ref and should only work in the method that created it. It seems to work ok, but I'll make it global cos the book said I should, and it may avoid future hassles. */ JNIEXPORT void JNICALL Java_org_greenstone_mgpp_MGPPWrapper_initIDs (JNIEnv *j_env, jclass j_cls) { FID_mgpp_data = j_env->GetFieldID(j_cls, "mgpp_data_ptr_", "J"); //a long-"J" if (FID_mgpp_data==NULL) { cerr <<"MGPP JNI: field mgpp_data_ptr_ not found"<GetFieldID(j_cls, "mgpp_query_result_", "Lorg/greenstone/mgpp/MGPPQueryResult;"); // an object -"L;" if (FID_query_result==NULL) { cerr <<"MGPP JNI: field mgpp_query_result_ not found"<FindClass("org/greenstone/mgpp/MGPPQueryResult"); MID_addDoc = j_env->GetMethodID(JC_MGPPQueryResult, "addDoc", "(JF)V"); if (MID_addDoc==NULL) { cerr <<"MGPP JNI: addDoc method not found"<GetMethodID(JC_MGPPQueryResult, "addTerm", "(Ljava/lang/String;Ljava/lang/String;IJJ[Ljava/lang/String;)V"); if (MID_addTerm==NULL) { cerr <<"MGPP JNI: method addTerm not found"<GetMethodID(JC_MGPPQueryResult, "setTotalDocs", "(J)V"); if (MID_setTotalDocs==NULL) { cerr <<"MGPP JNI: method setTotalDocs not found"<GetMethodID(JC_MGPPQueryResult, "clear", "()V"); if (MID_clearResult==NULL) { cerr <<"MGPP JNI: method clear not found"<GetMethodID(JC_MGPPQueryResult, "setSyntaxError", "(Z)V"); if (MID_clearResult==NULL) { cerr <<"MGPP JNI: method setSyntaxError not found"<FindClass("java/lang/String"); if (local_CID_String==NULL) { cerr <<"MGPP JNI: java String class not found"<NewGlobalRef(local_CID_String); /* The local reference is no longer useful */ j_env->DeleteLocalRef(local_CID_String); /* Is the global reference created successfully? */ if (CID_String == NULL) { return; /* out of memory exception thrown */ } } } /* the java side MGPPWrapper has a pointer to a C++ object - MGPPWrapperData initialise this and set the pointer */ JNIEXPORT jboolean JNICALL Java_org_greenstone_mgpp_MGPPWrapper_initCppSide (JNIEnv *j_env, jobject j_obj){ MGPPWrapperData * data = new MGPPWrapperData(); j_env->SetIntField(j_obj, FID_mgpp_data, (long)data); return true; } //**************************************************** // retrieve a document //**************************************************** /* returns a document from mgpp as a string Note: TextData isn't cached - just reloaded each time */ JNIEXPORT jstring JNICALL Java_org_greenstone_mgpp_MGPPWrapper_getDocument (JNIEnv *j_env, jobject j_obj, jstring j_text_name, jstring j_level, jlong j_docnum) { #ifdef __WIN32__ const char* base_dir = ""; #else const char* base_dir = "/"; #endif const char * text_name = j_env->GetStringUTFChars(j_text_name, NULL); if (text_name==NULL) { return NULL; } const char * level = j_env->GetStringUTFChars( j_level, NULL); if (level==NULL) { j_env->ReleaseStringUTFChars(j_text_name, text_name); return NULL; } // does this work alright? j_docnum is a long (64 bit) unsigned long docnum = j_docnum; TextData td; // cast to char* otherwise complains about const td.LoadData((char *)base_dir, (char *)text_name); UCArray mg_level; SetCStr(mg_level, level); UCArray docText; docText.clear(); // get the actual text if (!GetDocText(td, mg_level, docnum, docText)) { cerr <<"MGPP JNI: couldn't retrieve doc text"<NewStringUTF(doc); // release any gets j_env->ReleaseStringUTFChars(j_text_name, text_name); j_env->ReleaseStringUTFChars(j_level, level); // free any C++ stuff delete doc; return result; } //****************************************** // do a query // **************************************** /* load the IndexData - cached for querying */ JNIEXPORT jboolean JNICALL Java_org_greenstone_mgpp_MGPPWrapper_loadIndexData (JNIEnv *j_env, jobject j_obj, jstring j_index_name) { jint data_ptr = j_env->GetIntField(j_obj, FID_mgpp_data); MGPPWrapperData * data = (MGPPWrapperData *)data_ptr; #ifdef __WIN32__ const char* base_dir = ""; #else const char* base_dir = "/"; #endif const char * index_name = j_env->GetStringUTFChars( j_index_name, NULL); if (index_name==NULL) { return false; } jboolean j_result=false; // why doesn't this complain about const?? if (data->indexData->LoadData(base_dir, index_name)) { j_result=true; } // release any gets j_env->ReleaseStringUTFChars(j_index_name, index_name); return j_result; } /* unload the data */ JNIEXPORT jboolean JNICALL Java_org_greenstone_mgpp_MGPPWrapper_unloadIndexData (JNIEnv *j_env, jobject j_obj) { jint data_ptr = j_env->GetIntField(j_obj, FID_mgpp_data); MGPPWrapperData * data = (MGPPWrapperData *)data_ptr; data->indexData->UnloadData(); return true; } /* do the actual query - the results are written to query_result held on the java side */ JNIEXPORT void JNICALL Java_org_greenstone_mgpp_MGPPWrapper_runQuery (JNIEnv *j_env, jobject j_obj, jstring j_query){ jthrowable exc; // an exception - check if something funny has happened const char *query = j_env->GetStringUTFChars(j_query, NULL); if (query==NULL) { return; // exception already thrown } // turn to UCArray for mgpp and then release the string UCArray queryArray; SetCStr(queryArray, query); j_env->ReleaseStringUTFChars(j_query, query); // the query data MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data); // the result to write to jobject result_ptr = j_env->GetObjectField(j_obj, FID_query_result); if (result_ptr==NULL) { cerr <<"couldn't access the result to write to"<CallVoidMethod(result_ptr, MID_clearResult); exc = j_env->ExceptionOccurred(); // this catches teh exception I think - it //wont be thrown any further if (exc) { j_env->ExceptionDescribe(); return; } // the mgpp QueryResult that we will use ExtQueryResult queryResult; QueryNode * queryTree = NULL; // parse the query string into a tree structure queryTree = ParseQuery(queryArray, data->defaultBoolCombine, data->defaultStemMethod); if (queryTree == NULL) { // invalid syntax j_env->CallVoidMethod(result_ptr, MID_setSyntaxError, true); cerr << "MGPPWrapperImpl: invalid query syntax!!\n"; return; } // print the query PrintNode (cout, queryTree); // finally, do the query MGQuery(*(data->indexData), *(data->queryInfo), queryTree, queryResult, data->level); delete queryTree; // convert queryResult to the java side version // use levels rather than docs of ExtQueryResult // CallVoidMethod(obj, method id, args to method) for (int i=0; iCallVoidMethod(result_ptr, MID_addDoc, doc, rank); exc = j_env->ExceptionOccurred(); if (exc) { j_env->ExceptionDescribe(); return; } } // actual num of docs jlong total = queryResult.actualNumDocs; j_env->CallVoidMethod(result_ptr, MID_setTotalDocs, total); exc = j_env->ExceptionOccurred(); if (exc) { j_env->ExceptionDescribe(); return; } // the terms for (int j=0; jNewStringUTF(GetCStr(tf.term)); jstring tag = j_env->NewStringUTF(GetCStr(tf.tag)); jint stem = tf.stemMethod; jlong match = tf.matchDocs; jlong freq = tf.termFreq; jobjectArray equivs=NULL; jstring empty = j_env->NewStringUTF(""); // the initial object to fill the array jint num_equivs = tf.equivTerms.size(); equivs = j_env->NewObjectArray(num_equivs, CID_String, empty); if (equivs==NULL) { cerr<<"couldn't create object array"<NewStringUTF(GetCStr(tf.equivTerms[k])); j_env->SetObjectArrayElement(equivs, k, equiv); } j_env->CallVoidMethod(result_ptr, MID_addTerm, term, tag, stem, match, freq, equivs); exc = j_env->ExceptionOccurred(); if (exc) { j_env->ExceptionDescribe(); return; } } } } JNIEXPORT void JNICALL Java_org_greenstone_mgpp_MGPPWrapper_setStem (JNIEnv *j_env, jobject j_obj, jboolean j_on) { MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data); if (j_on) { data->defaultStemMethod |= 2; } else { data->defaultStemMethod &= 0xd; } } JNIEXPORT void JNICALL Java_org_greenstone_mgpp_MGPPWrapper_setCase (JNIEnv *j_env, jobject j_obj, jboolean j_on) { MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data); if (j_on) { data->defaultStemMethod |= 1; } else { data->defaultStemMethod &= 0xe; } } JNIEXPORT void JNICALL Java_org_greenstone_mgpp_MGPPWrapper_setMaxDocs (JNIEnv *j_env, jobject j_obj, jint j_max) { MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data); data->queryInfo->maxDocs=j_max; } JNIEXPORT void JNICALL Java_org_greenstone_mgpp_MGPPWrapper_setSortByRank (JNIEnv *j_env, jobject j_obj, jboolean j_on) { MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data); data->queryInfo->sortByRank=j_on; } JNIEXPORT void JNICALL Java_org_greenstone_mgpp_MGPPWrapper_setReturnTerms(JNIEnv *j_env, jobject j_obj, jboolean j_on) { MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data); data->queryInfo->needTermFreqs = j_on; } JNIEXPORT void JNICALL Java_org_greenstone_mgpp_MGPPWrapper_setQueryLevel(JNIEnv *j_env, jobject j_obj, jstring j_level){ MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data); const char * level = j_env->GetStringUTFChars(j_level, NULL); if (level==NULL) { return; // exception already thrown } data->queryInfo->docLevel.clear(); SetCStr(data->queryInfo->docLevel, level); // release the java stuff j_env->ReleaseStringUTFChars(j_level, level); } JNIEXPORT void JNICALL Java_org_greenstone_mgpp_MGPPWrapper_setReturnLevel(JNIEnv *j_env, jobject j_obj, jstring j_level){ MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data); const char * level = j_env->GetStringUTFChars(j_level, NULL); if (level==NULL) { return; // exception already thrown } data->level.clear(); SetCStr(data->level, level); // release the java stuff j_env->ReleaseStringUTFChars(j_level, level); } JNIEXPORT void JNICALL Java_org_greenstone_mgpp_MGPPWrapper_setMatchMode (JNIEnv *j_env, jobject j_obj, jint j_mode){ MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data); data->defaultBoolCombine=j_mode; } JNIEXPORT jstring JNICALL Java_org_greenstone_mgpp_MGPPWrapper_getQueryParams (JNIEnv *j_env, jobject j_obj){ MGPPWrapperData * data = (MGPPWrapperData *)j_env->GetIntField(j_obj, FID_mgpp_data); // print the data to a stringstream, then convert to char*, then to //jstring stringstream output; output << "Query params:"<indexData->basePath<<"/"<indexData->filename<queryInfo->docLevel)<level)<defaultStemMethod&1)<defaultStemMethod&2)<queryInfo->sortByRank<defaultBoolCombine==1?"all":"some")<queryInfo->maxDocs<NewStringUTF(result); delete (char *)result; return j_result; }