scriptators/tcl/Tclator.cpp (317 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include <tcl.h> #include "uima/api.hpp" #define THREAD_PROTECTION #ifdef THREAD_PROTECTION #include "ThreadAnnotator.h" #endif using namespace uima; using namespace std; #define MODULENAME "Tclator" extern "C" { int Tclator_Init(Tcl_Interp * interp); } #ifdef LINUX // Allow use of single threaded Tcl interpreter in multithreaded environments #define MUTEX_DEFINE static pthread_mutex_t mutex; #define MUTEX_INIT pthread_mutex_init(&mutex,0); #define MUTEX_LOCK pthread_mutex_lock(&mutex); #define MUTEX_UNLOCK pthread_mutex_unlock(&mutex); #define MUTEX_ALLOCATE pthread_mutex_t Tclator::mutex = PTHREAD_MUTEX_INITIALIZER; #else // Not supported yet #define MUTEX_DEFINE #define MUTEX_INIT #define MUTEX_LOCK #define MUTEX_UNLOCK #define MUTEX_ALLOCATE #endif // copied from SwigGenerated code // this function requires the SWIG code to be compiled with // SWIGRUNTIME defined to be "", otherwise this function is static // and does not scope outside of the library #if !defined(SWIG_GLOBAL) && !defined(SWIGRUNTIME) // SWIG 1.3.29 or better #include "uimatclwrap.h" #endif const char *default_methods = "proc initialize {ac} {}\n" "proc typeSystemInit {ts} {}\n" "proc destroy {} {}\n" "proc process {cas rs} {}\n" "proc reconfigure {} {}\n" "proc batchProcessComplete {} {}\n" "proc collectionProcessComplete {} {}\n"; class Tclator : public Annotator { int debug; MUTEX_DEFINE swig_type_info *cas_type, *rs_type, *ts_type; Tcl_Interp *interp; Tcl_Obj *commands[7]; enum CMDS { INITIALIZE, TYPESYSTEMINIT, DESTROY, PROCESS, RECONFIGURE, BATCHPROCESSCOMPLETE, COLLECTIONPROCESSCOMPLETE }; public: Tclator() : interp(0) {} // We construct a perl interpreter in initialize - it lives for the // life of the annotator - even if reconfigure happens. Reconfigure // and intialize both set dirty so the source code in the source file // and contained in the type system are evaluated. TyErrorId initialize(AnnotatorContext &ac) { swig_type_info *ac_type; char srcfile[1000 + 256]; if (ac.isParameterDefined("DebugLevel")) { ac.extractValue("DebugLevel", debug); } if (debug > 0) { cerr<< MODULENAME ": Initialize - debug=" << debug <<endl; } if (!ac.isParameterDefined("SourceFile")) { cerr<< MODULENAME ": Missing Tcl SourceFile" <<endl; return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } UnicodeString fn; ac.extractValue(UnicodeString("SourceFile"), fn); if (fn == "") { cerr<< MODULENAME ": Empty Tcl SourceFile" <<endl; return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } // cerr << fn << endl; UErrorCode err = U_ZERO_ERROR; fn.extract(srcfile,sizeof(srcfile),0,err); if (U_FAILURE(err)) { cerr << MODULENAME ": Unable to extract parameter, got " << u_errorName(err) << endl; return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } if (interp == 0) { // this seems to make windows work // would be nice to know argv[0] somehow Tcl_FindExecutable( 0 ); interp = Tcl_CreateInterp(); if (interp == 0) { cerr << MODULENAME ": failed to create interpreter" << endl; return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } int tclret = Tcl_Init(interp); if (tclret != TCL_OK) { cerr << MODULENAME ": failed to init interpreter - " << Tcl_GetStringResult(interp) << endl; return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } if (Tclator_Init(interp) != TCL_OK) { cerr << MODULENAME ": failed to init tclator package" << endl; return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } commands[INITIALIZE] = Tcl_NewStringObj("initialize", -1); commands[TYPESYSTEMINIT] = Tcl_NewStringObj("typeSystemInit", -1); commands[RECONFIGURE] = Tcl_NewStringObj("reconfigure", -1); commands[PROCESS] = Tcl_NewStringObj("process", -1); commands[DESTROY] = Tcl_NewStringObj("destroy", -1); commands[BATCHPROCESSCOMPLETE] = Tcl_NewStringObj("batchProcessComplete", -1); commands[COLLECTIONPROCESSCOMPLETE] = Tcl_NewStringObj("collectionProcessComplete", -1); for (unsigned int i=0; i<7; ++i) Tcl_IncrRefCount(commands[i]); if (Tcl_Eval(interp, default_methods) != TCL_OK) { cerr << MODULENAME << ": Error - " << Tcl_GetStringResult(interp) << endl; return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } if (Tcl_EvalFile(interp, srcfile) != TCL_OK) { cerr << MODULENAME << ": Error - " << Tcl_GetStringResult(interp) << endl; return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } // this is a static variable because of the way that SWIG's // initialization code is written. static swig_module_info *module = 0; if (module == 0) { MUTEX_INIT MUTEX_LOCK module = SWIG_Tcl_GetModule(interp); } else { MUTEX_LOCK SWIG_Tcl_SetModule(interp, module); } if (!module) { cerr << MODULENAME ": could not get Tcl swig module" << endl; MUTEX_UNLOCK return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } ts_type = SWIG_TypeQueryModule(module,module, "TypeSystem *"); if (!ts_type) { cerr << MODULENAME ": could lookup TypeSystem type in swig" << endl; MUTEX_UNLOCK return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } ac_type = SWIG_TypeQueryModule(module,module, "AnnotatorContext *"); if (!ac_type) { cerr << MODULENAME ": could lookup AnnotatorContext type in swig" << endl; MUTEX_UNLOCK return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } cas_type = SWIG_TypeQueryModule(module,module, "CAS *"); if (!cas_type) { cerr << MODULENAME ": could lookup cas type in swig" << endl; MUTEX_UNLOCK return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } rs_type = SWIG_TypeQueryModule(module,module, "ResultSpecification *"); if (!rs_type) { cerr << MODULENAME ": could lookup rs type in swig" << endl; MUTEX_UNLOCK return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } } Tcl_Obj *args[2]; args[0] = commands[INITIALIZE]; args[1] = SWIG_Tcl_NewPointerObj( reinterpret_cast<void *>( const_cast<AnnotatorContext *>(&ac)), ac_type, 0); Tcl_IncrRefCount(args[0]); Tcl_IncrRefCount(args[1]); int rc = Tcl_EvalObjv(interp, 2, args, 0); Tcl_DecrRefCount(args[0]); Tcl_DecrRefCount(args[1]); if (rc != TCL_OK) { cerr << MODULENAME " initialize error " << Tcl_GetStringResult(interp) << endl; MUTEX_UNLOCK return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } MUTEX_UNLOCK return UIMA_ERR_NONE; } TyErrorId reconfigure() { if (interp == 0) { cerr << MODULENAME ": not initialized in reconfigure" << endl; return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } if (debug > 100) { cerr<< MODULENAME ": reconfigure" <<endl; } MUTEX_LOCK Tcl_Obj *args[1]; args[0] = commands[RECONFIGURE]; Tcl_IncrRefCount(args[0]); int rc = Tcl_EvalObjv(interp, 1, args, 0); Tcl_DecrRefCount(args[0]); if ( rc != TCL_OK) { cerr << MODULENAME " reconfigure error " << Tcl_GetStringResult(interp) << endl; MUTEX_UNLOCK return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } MUTEX_UNLOCK return UIMA_ERR_NONE; } TyErrorId typeSystemInit(TypeSystem const &ts) { if (interp == 0) { cerr << MODULENAME ": not initialized in typeSystemInit" << endl; return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } if (debug > 100) { cerr<< MODULENAME ": typeSystemInit" <<endl; } MUTEX_LOCK Tcl_Obj *args[2]; args[0] = commands[TYPESYSTEMINIT]; args[1] = SWIG_Tcl_NewPointerObj( reinterpret_cast<void *>( const_cast<TypeSystem *>(&ts)), ts_type, 0); Tcl_IncrRefCount(args[0]); Tcl_IncrRefCount(args[1]); int rc = Tcl_EvalObjv(interp, 2, args, 0); Tcl_DecrRefCount(args[1]); Tcl_DecrRefCount(args[0]); if (rc != TCL_OK) { cerr << MODULENAME " typeSystemInit error " << Tcl_GetStringResult(interp) << endl; MUTEX_UNLOCK return UIMA_ERR_USER_ANNOTATOR_COULD_NOT_INIT; } MUTEX_UNLOCK return UIMA_ERR_NONE; } /** * call the UIMA Annotator to deinitialize itself based on a UIMA engine * and return a UIMA error code */ TyErrorId destroy() { if (debug > 100) { cerr<< MODULENAME ": destroy " << endl; } if (interp != 0) { MUTEX_LOCK Tcl_Obj *args[1]; args[0] = commands[DESTROY]; Tcl_IncrRefCount(args[0]); if (Tcl_EvalObjv(interp, 1, args, 0) != TCL_OK) { cerr << MODULENAME " destroy error (ignored) " << Tcl_GetStringResult(interp) << endl; } Tcl_DecrRefCount(args[0]); for (unsigned int i=0; i<7; ++i) { if (commands[i]) Tcl_DecrRefCount(commands[i]); commands[i] = 0; } Tcl_DeleteInterp(interp); interp = 0; MUTEX_UNLOCK } return (TyErrorId)UIMA_ERR_NONE; } /** * call the UIMA Annotator to perform its duty based on a UIMA engine * and return a UIMA error code */ TyErrorId process(CAS &_cas, ResultSpecification const & _rs) { if (debug > 100) { cerr<< MODULENAME ": process " << endl; } TyErrorId rc = UIMA_ERR_NONE; MUTEX_LOCK Tcl_Obj *args[3]; args[0] = commands[PROCESS]; args[1] = SWIG_Tcl_NewPointerObj( reinterpret_cast<void *>( &_cas), cas_type, 0); args[2] = SWIG_Tcl_NewPointerObj( reinterpret_cast<void *>( const_cast<ResultSpecification *>(&_rs)), rs_type, 0); Tcl_IncrRefCount(args[0]); Tcl_IncrRefCount(args[1]); Tcl_IncrRefCount(args[2]); int trc = Tcl_EvalObjv(interp, 3, args, 0); Tcl_DecrRefCount(args[2]); Tcl_DecrRefCount(args[1]); Tcl_DecrRefCount(args[0]); if (trc != TCL_OK) { cerr << MODULENAME " process error (ignored) " << Tcl_GetStringResult(interp) << endl; rc = UIMA_ERR_USER_ANNOTATOR_COULD_NOT_PROCESS; } MUTEX_UNLOCK return rc; } /** * call the UIMA Annotator batchProcessComplete method * and return a UIMA error code */ TyErrorId batchProcessComplete() { if (debug > 100) { cerr<< MODULENAME ": batchProcessComplete " << endl; } TyErrorId rc = UIMA_ERR_NONE; MUTEX_LOCK Tcl_Obj *args[1]; args[0] = commands[BATCHPROCESSCOMPLETE]; Tcl_IncrRefCount(args[0]); int trc = Tcl_EvalObjv(interp, 1, args, 0); Tcl_DecrRefCount(args[0]); if (trc != TCL_OK) { cerr << MODULENAME " batchProcessComplete error (ignored) " << Tcl_GetStringResult(interp) << endl; rc = UIMA_ERR_USER_ANNOTATOR_COULD_NOT_PROCESS; } MUTEX_UNLOCK return rc; } /** * call the UIMA Annotator collectionProcessComplete method * and return a UIMA error code */ TyErrorId collectionProcessComplete() { if (debug > 100) { cerr<< MODULENAME ": collectionProcessComplete " << endl; } TyErrorId rc = UIMA_ERR_NONE; MUTEX_LOCK Tcl_Obj *args[1]; args[0] = commands[COLLECTIONPROCESSCOMPLETE]; Tcl_IncrRefCount(args[0]); int trc = Tcl_EvalObjv(interp, 1, args, 0); Tcl_DecrRefCount(args[0]); if (trc != TCL_OK) { cerr << MODULENAME " collectionProcessComplete error (ignored) " << Tcl_GetStringResult(interp) << endl; rc = UIMA_ERR_USER_ANNOTATOR_COULD_NOT_PROCESS; } MUTEX_UNLOCK return rc; } }; MUTEX_ALLOCATE #ifdef THREAD_PROTECTION MAKE_AE(ThreadAnnotator<Tclator>); #else MAKE_AE(Tclator); #endif /* <EOF> */