in src/framework/annotator_mgr.cpp [438:587]
TyErrorId AnnotatorManager::launchProcessDocument(CAS & cas, ResultSpecification const & crResultSpec) {
/*
This works as follows:
The passes result spec is copied and for each delegate AE, it is determined
(via shouldEngineBeCalled()) which TOFs of the result spec should be passed to the
TAE (if it should be called at all). After the call to the delegate, those TOFs are
removed from the copied result spec. At the end, this result spec is then empty (ideally).
Note that for this to work, you have to add all needed intermediate results to the process()
call on the TAE even if those are not the results the application is interested in.
E.g., if I have a tokenizer and a summarizer and my aplication is only interested in summaries,
it nonetheless must sepcify that it needs tokens, sentences, and paragraphs because this is what
the summarizer needs as input.
*/
util::Trace clTrace(util::enTraceDetailLow, UIMA_TRACE_ORIGIN, UIMA_TRACE_COMPID_ANNOTATOR_MGR);
UIMA_ANNOTATOR_TIMING(iv_clTimerLaunchProcess.start());
TyAnnotatorEntries::iterator it;
TyErrorId utErrorId = UIMA_ERR_NONE;
TyErrorId utRetVal = UIMA_ERR_NONE;
assert( EXISTS(iv_pEngine) );
size_t uiNbrOfSkippedAnnotators = 0;
CAS * tcas=NULL;
// copy the result spec
ResultSpecification resSpec = crResultSpec;
++iv_uiNbrOfDocsProcessed;
assert(iv_bIsInitialized);
assert(!iv_vecEntries.empty());
for (it = iv_vecEntries.begin(); it != iv_vecEntries.end(); ++it) {
EngineEntry & rEntry = (*it);
AnalysisEngine * pEngine = rEntry.iv_pEngine;
uima::internal::CapabilityContainer * pCapContainer = rEntry.iv_pCapabilityContainer;
assert(EXISTS(pEngine));
assert(EXISTS(pCapContainer));
#ifdef DEBUG_VERBOSE
UIMA_TPRINT("=========================================");
UIMA_TPRINT("----------- ResultSpec before process():");
resSpec.print(cout);
#endif
UIMA_TRACE_STREAM_ARG(clTrace, "ASB checks engine", pEngine->getAnalysisEngineMetaData().getName() );
UIMA_TPRINT("--------- Checking annotator: " << pEngine->getAnalysisEngineMetaData().getName());
vector<TypeOrFeature> tofsToBeRemoved;
bool callEngine=true;
bool requiresTCas=true;
if (cas.isBackwardCompatibleCas()) {
tcas = &cas;
}
//this populates the tofsToBeRemoved vector so always call it
callEngine = shouldEngineBeCalled(*pCapContainer,
resSpec,
cas.getDocumentAnnotation().getLanguage(),
tofsToBeRemoved);
//check the FlowConstraintType specified in the aggregate engine
//if CapabilityLanguageFlow whether engine is called is
//determined by shouldEngineBeCalled()
AnnotatorContext & rANC = iv_pEngine->getAnnotatorContext();
AnalysisEngineDescription const & crTAESpecifier = rANC.getTaeSpecifier();
FlowConstraints const * pFlow = crTAESpecifier.getAnalysisEngineMetaData()->getFlowConstraints();
FlowConstraints * flow = CONST_CAST(FlowConstraints *, pFlow);
FlowConstraints::EnFlowType flowType = flow->getFlowConstraintsType();
//if FixedFlow specified all engines are always called so reset callEngine is true
if (flowType == FlowConstraints::FIXED) {
callEngine=true;
}
if ( callEngine ) {
UIMA_TPRINT("----------- engine will be processed");
UIMA_TRACE_STREAM(clTrace, "Engine will be called");
// create ResultSpec for annotator
// this must be done because an annotator should only be called with the result spec
// that its XML file indicates.
ResultSpecification annResSpec;
vector<TypeOrFeature>::const_iterator citTOF;
for (citTOF = tofsToBeRemoved.begin(); citTOF != tofsToBeRemoved.end(); ++citTOF) {
assert( (*citTOF).isValid() );
annResSpec.add(*citTOF);
UIMA_TRACE_STREAM_ARG(clTrace, " engine is called with result spec", (*citTOF).getName() );
}
/// does engine expect a TCas
//AEs that declare at least one input or output SofA should be sent the base CAS.
//Otherwise they must be sent a TCAS.
const AnalysisEngineMetaData::TyVecpCapabilities & vecCap = pEngine->getAnalysisEngineMetaData().getCapabilites();
AnalysisEngineMetaData::TyVecpCapabilities::const_iterator itCap;
for (size_t i=0; i < vecCap.size(); i++) {
Capability * cap = vecCap.at(i);
Capability::TyVecCapabilitySofas inputSofa = cap->getCapabilitySofas(Capability::INPUTSOFA);
Capability::TyVecCapabilitySofas outputSofa = cap->getCapabilitySofas(Capability::OUTPUTSOFA);
if (inputSofa.size() > 0 || outputSofa.size() > 0) {
requiresTCas = false;
break;
}
}
if (requiresTCas) {
SofaFS defSofa = cas.getSofa(pEngine->getAnnotatorContext().mapToSofaID(CAS::NAME_DEFAULT_TEXT_SOFA));
if (!defSofa.isValid()) {
//TODO: throw exception
cerr << "could not get default text sofa " << endl;
return 99;
}
tcas = cas.getView(defSofa);
utErrorId = pEngine->process(*tcas, annResSpec);
} else {
utErrorId = ((AnalysisEngine*) pEngine)->process(cas, annResSpec);
}
if (utErrorId != UIMA_ERR_NONE) {
clTrace.dump(_TEXT("Error"), (long) utErrorId);
utRetVal = utErrorId; /* I know, this overwrites a previous error */
} else {
// now remove TOFs from ResultSpec
vector<TypeOrFeature>::const_iterator citTOF;
for (citTOF = tofsToBeRemoved.begin(); citTOF != tofsToBeRemoved.end(); ++citTOF) {
assert( (*citTOF).isValid() );
resSpec.remove(*citTOF);
}
}
} else {
assert( tofsToBeRemoved.empty() );
UIMA_TPRINT("----------- engine will *not* be processed");
++uiNbrOfSkippedAnnotators;
}
} /* e-o-for */
/* in case there was no error but not any annotator which generates a target type
has been caled for process, we have an error */
UIMA_TPRINT("Annotators skipped due to unsupport lang: " << uiNbrOfSkippedAnnotators);
UIMA_TPRINT("Overall number of annotators: " << iv_vecEntries.size() );
if ( (utRetVal == UIMA_ERR_NONE)
&& (uiNbrOfSkippedAnnotators > 0)
&& (uiNbrOfSkippedAnnotators == iv_vecEntries.size())
&& (crResultSpec.getSize() > 0) ) {
// utRetVal = UIMA_ERR_ANNOTATOR_MGR_LANG_NOT_SUPPORTED_FOR_ANNOTATOR;
iv_pEngine->getAnnotatorContext().getLogger().logWarning("All annotators skipped (maybe unsupported language)");
}
UIMA_ANNOTATOR_TIMING(iv_clTimerLaunchProcess.stop());
return(utRetVal);
}