| /** \file internal_engine_base.cpp . |
| ----------------------------------------------------------------------------- |
| |
| |
| * 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. |
| |
| ----------------------------------------------------------------------------- |
| |
| Description: |
| |
| ----------------------------------------------------------------------------- |
| |
| |
| -------------------------------------------------------------------------- */ |
| |
| |
| /* ----------------------------------------------------------------------- */ |
| /* Include dependencies */ |
| /* ----------------------------------------------------------------------- */ |
| //#define DEBUG_VERBOSE 1 |
| |
| #include "uima/pragmas.hpp" |
| |
| #include "uima/macros.h" |
| #include "uima/internal_engine_base.hpp" |
| #include "uima/msg.h" |
| #include "uima/annotator_context.hpp" |
| #include "uima/log.hpp" |
| #include "uima/lowlevel_typesystem.hpp" |
| #include "uima/lowlevel_indexrepository.hpp" |
| #include "uima/casdefinition.hpp" |
| #include "uima/internal_casimpl.hpp" |
| #include "uima/trace.hpp" |
| |
| /* ----------------------------------------------------------------------- */ |
| /* Constants */ |
| /* ----------------------------------------------------------------------- */ |
| |
| /* ----------------------------------------------------------------------- */ |
| /* Forward declarations */ |
| /* ----------------------------------------------------------------------- */ |
| |
| /* ----------------------------------------------------------------------- */ |
| /* Types / Classes */ |
| /* ----------------------------------------------------------------------- */ |
| |
| /* ----------------------------------------------------------------------- */ |
| /* Implementation */ |
| /* ----------------------------------------------------------------------- */ |
| namespace uima { |
| namespace internal { |
| |
| uima::internal::EngineBase & EngineBase::promoteEngine( uima::AnalysisEngine & engine) { |
| return (uima::internal::EngineBase&) engine; |
| } |
| |
| EngineBase::EngineBase(AnnotatorContext & rANC, bool bOwnsANC, |
| bool bOwnsTAESpecififer, |
| uima::internal::CASDefinition & casDef, bool ownsCasDef) |
| : |
| iv_pAnnotatorContext( & rANC), |
| iv_bOwnsANC(bOwnsANC), |
| iv_bOwnsTAESpec(bOwnsTAESpecififer), |
| iv_casDefinition( & casDef), |
| iv_ownsCASDefinition(ownsCasDef) { |
| iv_casHolder = NULL; |
| } |
| |
| EngineBase::~EngineBase() { |
| if (iv_bOwnsTAESpec) { |
| delete iv_pAnnotatorContext->getTAESpec(); |
| } |
| if (iv_bOwnsANC) { |
| delete iv_pAnnotatorContext; |
| } |
| if (iv_ownsCASDefinition) { |
| delete iv_casDefinition; |
| } |
| if (iv_casHolder) { |
| delete iv_casHolder; |
| } |
| } |
| |
| /** |
| * pretty simple CAS compatibility check: Just check if they |
| * have the same type system and index definition. |
| */ |
| void EngineBase::checkCASCompatibility(CAS const & cas) const { |
| uima::internal::CASImpl const & tcasImpl = uima::internal::CASImpl::promoteCAS(cas); |
| if ( (&tcasImpl.getHeap().getTypeSystem()) != (&iv_casDefinition->getTypeSystem()) |
| || (& tcasImpl.getIndexRepository().getIndexDefinition()) != (& iv_casDefinition->getIndexDefinition()) ) { |
| UIMA_EXC_THROW_NEW(CASIncompatibilityException, |
| UIMA_ERR_ENGINE_INCOMPATIBLE_CAS, |
| UIMA_MSG_ID_EXC_INCOMPATIBLE_CAS, |
| UIMA_MSG_ID_EXCON_PROCESSING_CAS, |
| ErrorInfo::recoverable); |
| } |
| } |
| |
| |
| bool EngineBase::checkAndSetCallingSequenceInitialize() { |
| if (iv_state.getState() != EngineState::enEngineState_readyForInit) { |
| return false; |
| } |
| iv_state.setToState(EngineState::enEngineState_readyForProcessOrReconfigOrDeinit); |
| return true; |
| } |
| |
| |
| bool EngineBase::checkAndSetCallingSequenceDestroy() { |
| if ( (iv_state.getState() != EngineState::enEngineState_readyForProcessOrReconfigOrDeinit) ) { |
| return false; |
| } |
| |
| iv_state.setToState(EngineState::enEngineState_readyForDeletion); |
| return true; |
| } |
| |
| bool EngineBase::checkAndSetCallingSequenceProcess() { |
| UIMA_TPRINT("state: " << iv_state.getState()); |
| if (iv_state.getState() != EngineState::enEngineState_readyForProcessOrReconfigOrDeinit) { |
| return false; |
| } |
| // dont change state |
| return true; |
| } |
| |
| |
| bool EngineBase::checkAndSetCallingSequenceReconfigure() { |
| if ( iv_state != EngineState::enEngineState_readyForProcessOrReconfigOrDeinit) { |
| return false; |
| } |
| // dont change state |
| return true; |
| } |
| |
| TyErrorId EngineBase::logError(util::Trace & rclTrace, TyErrorId utErrorId) { |
| if (utErrorId != UIMA_ERR_NONE) { |
| rclTrace.dump(_TEXT("Error:"), (size_t) utErrorId); |
| } |
| return(utErrorId); |
| } |
| |
| |
| |
| bool EngineBase::isInitialized(void) const { |
| switch (iv_state.getState()) { |
| case EngineState::enEngineState_readyForInit : |
| case EngineState::enEngineState_readyForDeletion : |
| return false; |
| case EngineState::enEngineState_readyForProcessOrReconfigOrDeinit : |
| return true; |
| } |
| assert(false); |
| return false; |
| } |
| |
| CAS * EngineBase::newCAS() const { |
| assert( EXISTS(iv_casDefinition) ); |
| assert( EXISTS(iv_pAnnotatorContext) ); |
| CAS* tmpCas = uima::internal::CASImpl::createCASImpl(* CONST_CAST(uima::internal::CASDefinition*, iv_casDefinition), *iv_pAnnotatorContext); |
| return tmpCas->getInitialView(); |
| } |
| |
| |
| void EngineBase::destroyIfNeeded() { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| |
| try { |
| if (iv_state == EngineState::enEngineState_readyForProcessOrReconfigOrDeinit) { |
| destroy(); |
| iv_state.assertMatch(EngineState::enEngineState_readyForDeletion); |
| } |
| } catch (ExcWinCException & rclException) { |
| // windows "exceptions" are really abort signals: we re-throw for app to handle |
| throw rclException; |
| } catch (Exception & rclException) { |
| clTrace.dump("Unexpected UIMACPP exception"); |
| clTrace.dump(rclException.asString().c_str()); |
| assertWithMsg(false, _TEXT("Unexpected UIMACPP exception in engine destructor")); //lint !e506: Constant value Boolean |
| } catch (exception & rclException) { |
| clTrace.dump("ANSI C++ exception"); |
| clTrace.dump(rclException.what()); |
| assertWithMsg(false, _TEXT("Unexpected ANSI C++ exception in engine destructor")); //lint !e506: Constant value Boolean |
| } |
| #ifdef NDEBUG |
| catch (...) { |
| /* this should never occur!!! */ |
| clTrace.dump(_TEXT("Unexpected exception")); |
| assertWithMsg(false, _TEXT("Unexpected unknown exception in engine destructor")); //lint !e506: Constant value Boolean |
| } |
| #endif |
| } |
| |
| |
| /** |
| * Gathers all output capabilities from the TAE specifier. |
| * This result spec is implicitly assumed when calling process(CAS) without a result spec. |
| */ |
| TyErrorId EngineBase::initializeCompleteResultSpec() { |
| iv_completeResultSpec.clear(); |
| |
| assert( EXISTS(iv_casDefinition) ); |
| uima::TypeSystem const & rTypeSystem = iv_casDefinition->getTypeSystem(); |
| |
| AnnotatorContext const & crANC = getAnnotatorContext(); |
| |
| AnalysisEngineMetaData::TyVecpCapabilities const & crVecCaps = crANC.getTaeSpecifier().getAnalysisEngineMetaData()->getCapabilites(); |
| AnalysisEngineMetaData::TyVecpCapabilities::const_iterator citCaps; |
| |
| for (citCaps = crVecCaps.begin(); citCaps != crVecCaps.end(); ++citCaps) { |
| Capability const * cpCap = * citCaps; |
| Capability::TyVecCapabilityTofs const & crTypes = cpCap->getCapabilityTypes(Capability::OUTPUT); |
| Capability::TyVecCapabilityTofs::const_iterator citTOFs; |
| for (citTOFs = crTypes.begin(); citTOFs != crTypes.end(); ++citTOFs) { |
| Type t = rTypeSystem.getType( *citTOFs ); |
| if (! t.isValid() ) { |
| ErrorInfo errInf( |
| ErrorMessage(UIMA_MSG_ID_UNKNOWN_FEATURE_IN_CAPBILITY_SPEC,(*citTOFs)), |
| UIMA_ERR_ANNOTATOR_MGR_CONFIG_INVALID_RESULTSPECIFICATION, |
| ErrorInfo::unrecoverable); |
| getAnnotatorContext().getLogger().logError(errInf); |
| return UIMA_ERR_ANNOTATOR_MGR_CONFIG_INVALID_RESULTSPECIFICATION; |
| } |
| iv_completeResultSpec.add(t); |
| } |
| |
| Capability::TyVecCapabilityTofs const & crFeatures = cpCap->getCapabilityFeatures(Capability::OUTPUT); |
| for (citTOFs = crFeatures.begin(); citTOFs != crFeatures.end(); ++citTOFs) { |
| Feature f = rTypeSystem.getFeatureByFullName(*citTOFs); |
| if (! f.isValid() ) { |
| ErrorInfo errInf( |
| ErrorMessage(UIMA_MSG_ID_UNKNOWN_FEATURE_IN_CAPBILITY_SPEC,(*citTOFs)), |
| UIMA_ERR_ANNOTATOR_MGR_CONFIG_INVALID_RESULTSPECIFICATION, |
| ErrorInfo::unrecoverable); |
| getAnnotatorContext().getLogger().logError(errInf); |
| return UIMA_ERR_ANNOTATOR_MGR_CONFIG_INVALID_RESULTSPECIFICATION; |
| } |
| iv_completeResultSpec.add(f); |
| } |
| |
| } |
| return UIMA_ERR_NONE; |
| } |
| |
| |
| TyErrorId EngineBase::initialize(AnalysisEngineDescription const & specifier) { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| |
| if (!checkAndSetCallingSequenceInitialize()) { |
| return logError(clTrace, UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE); |
| } |
| assert( (& specifier) == (&iv_pAnnotatorContext->getTaeSpecifier())); |
| // call implementation in subclass |
| TyErrorId utErrorId = initializeImpl(specifier); |
| if (utErrorId != UIMA_ERR_NONE) { |
| destroy(); |
| return utErrorId; |
| } |
| |
| utErrorId = initializeCompleteResultSpec(); |
| if (utErrorId != UIMA_ERR_NONE) { |
| destroy(); |
| return utErrorId; |
| } |
| |
| int numCasRequired = getCasInstancesRequiredImpl(); |
| if (numCasRequired > 0) { |
| utErrorId = iv_pAnnotatorContext->defineCASPool(numCasRequired); |
| } |
| |
| return utErrorId; |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| return rclException.getErrorInfo().getErrorId(); |
| } |
| |
| } |
| |
| |
| TyErrorId EngineBase::reinitTypeSystem() { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| TyErrorId utErrorId = reinitTypeSystemImpl(); |
| if (utErrorId != UIMA_ERR_NONE) { |
| destroy(); |
| return utErrorId; |
| } |
| |
| // we have to re-initialize the result spec since the types and features |
| // may have changed. |
| utErrorId = initializeCompleteResultSpec(); |
| if (utErrorId != UIMA_ERR_NONE) { |
| destroy(); |
| return utErrorId; |
| } |
| return utErrorId; |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| return rclException.getErrorInfo().getErrorId(); |
| } |
| |
| } |
| |
| |
| ResultSpecification const & EngineBase::getCompleteResultSpecification() const { |
| return iv_completeResultSpec; |
| } |
| |
| |
| TyErrorId EngineBase::destroy() { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| |
| if (!checkAndSetCallingSequenceDestroy()) { |
| return logError(clTrace, UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE); |
| } |
| return destroyImpl(); |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| return rclException.getErrorInfo().getErrorId(); |
| } |
| } |
| |
| TyErrorId EngineBase::reconfigure() { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| |
| if (!checkAndSetCallingSequenceReconfigure()) { |
| return logError(clTrace, UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE); |
| } |
| return reconfigureImpl(); |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| return rclException.getErrorInfo().getErrorId(); |
| } |
| |
| } |
| |
| |
| TyErrorId EngineBase::process(CAS & cas) { |
| try { |
| AnalysisEngine * engine = this; |
| return engine->process(cas, getCompleteResultSpecification()); |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| UIMA_EXC_RETHROW(rclException,NULL); |
| ///return rclException.getErrorInfo().getErrorId(); |
| } |
| |
| } |
| |
| TyErrorId EngineBase::process(CAS & cas, ResultSpecification const & resultSpec) { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| |
| if (!checkAndSetCallingSequenceProcess()) { |
| return logError(clTrace, UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE); |
| } |
| // (ee) WHY DO THIS CHECK??? |
| //checkCASCompatibility(cas); |
| |
| // Removed code that used to skip the processing if the document |
| // was empty, since not all Sofas have local text. (bll) |
| |
| return processImpl(cas, resultSpec); |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| //return rclException.getErrorInfo().getErrorId(); |
| UIMA_EXC_RETHROW(rclException,NULL); |
| } |
| |
| } |
| |
| |
| TyErrorId EngineBase::batchProcessComplete() { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| |
| if (!checkAndSetCallingSequenceProcess()) { |
| return logError(clTrace, UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE); |
| } |
| return batchProcessCompleteImpl(); |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| return rclException.getErrorInfo().getErrorId(); |
| } |
| |
| } |
| |
| TyErrorId EngineBase::collectionProcessComplete() { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| |
| if (!checkAndSetCallingSequenceProcess()) { |
| return logError(clTrace, UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE); |
| } |
| return collectionProcessCompleteImpl(); |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| return rclException.getErrorInfo().getErrorId(); |
| } |
| |
| } |
| |
| bool EngineBase::hasNext() { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| /** why do this ?? (bi) |
| if (!checkAndSetCallingSequenceProcess()) { |
| logError(clTrace, UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE); |
| return false; |
| } **/ |
| return hasNextImpl(); |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| throw rclException; |
| } |
| } |
| |
| CAS & EngineBase::next() { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| /** why do this (bi) |
| if (!checkAndSetCallingSequenceProcess()) { |
| logError(clTrace, UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE); |
| } **/ |
| return nextImpl(); |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| //return rclException.getErrorInfo().getErrorId(); |
| throw rclException; |
| } |
| } |
| |
| int EngineBase::getCasInstancesRequired() { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| |
| if (!checkAndSetCallingSequenceProcess()) { |
| logError(clTrace, UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE); |
| return 0; |
| } |
| return getCasInstancesRequiredImpl(); |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| //return rclException.getErrorInfo().getErrorId(); |
| throw rclException; |
| } |
| } |
| |
| CASIterator EngineBase::processAndOutputNewCASes(CAS & cas) { |
| try { |
| util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ENGINE); |
| |
| if (!checkAndSetCallingSequenceProcess()) { |
| logError(clTrace, UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE); |
| |
| UIMA_EXC_THROW_NEW(CASIteratorException, |
| UIMA_ERR_ENGINE_INVALID_CALLING_SEQUENCE, |
| UIMA_MSG_ID_EXCON_CALLING_ANNOTATOR_FUNCTION, |
| UIMA_MSG_ID_EXCON_CALLING_ANNOTATOR_FUNCTION, |
| ErrorInfo::unrecoverable); |
| } |
| TyErrorId rc = process(cas); |
| if (rc != UIMA_ERR_NONE) { |
| UIMA_EXC_THROW_NEW(CASIteratorException, |
| UIMA_ERR_PROCESS_OUTPUT_CAS, |
| UIMA_MSG_ID_EXCON_CALLING_ANNOTATOR_FUNCTION, |
| UIMA_MSG_ID_EXCON_CALLING_ANNOTATOR_FUNCTION, |
| ErrorInfo::unrecoverable); |
| } |
| return CASIterator(this); |
| } catch (Exception & rclException) { |
| getAnnotatorContext().getLogger().logError(rclException.getErrorInfo() ); |
| //return rclException.getErrorInfo().getErrorId(); |
| throw rclException; |
| } |
| } |
| |
| TyErrorId EngineBase::batchProcessCompleteImpl() { |
| return UIMA_ERR_NOT_YET_IMPLEMENTED; |
| } |
| |
| TyErrorId EngineBase::collectionProcessCompleteImpl() { |
| return UIMA_ERR_NOT_YET_IMPLEMENTED; |
| } |
| |
| } |
| } |
| |
| /* ----------------------------------------------------------------------- */ |
| |
| |
| |