// no new CASes are output; this cas is done being processed
// by that AnalysisEngine so clear the componentInfo
cas.setCurrentComponentInfo(null);
}
} else {
throw new AnalysisEngineProcessException(
AnalysisEngineProcessException.UNKNOWN_ID_IN_SEQUENCE,
new Object[] { nextAeKey });
}
}
//ParallelStep (TODO: refactor out common parts with SimpleStep?)
else if (nextStep instanceof ParallelStep) {
//create modifiable list of destinations
List<String> destinations = new LinkedList<String>(((ParallelStep)nextStep).getAnalysisEngineKeys());
//iterate over all destinations, removing them from the list as we go
while (!destinations.isEmpty()) {
String nextAeKey = destinations.get(0);
destinations.remove(0);
//execute this step as we would a single step
AnalysisEngine nextAe = (AnalysisEngine) mComponentAnalysisEngineMap.get(nextAeKey);
if (nextAe != null) {
// invoke next AE in flow
CasIterator casIter = null;
CAS outputCas = null; //used if the AE we call outputs a new CAS
try {
casIter = nextAe.processAndOutputNewCASes(cas);
if (casIter.hasNext()) {
outputCas = casIter.next();
}
}
catch(Exception e) {
//ask the FlowController if we should continue
//TODO: should this be configurable?
if (!flow.continueOnFailure(nextAeKey, e)) {
throw e;
}
else {
UIMAFramework.getLogger(CLASS_NAME).logrb(Level.FINE, CLASS_NAME.getName(), "processUntilNextOutputCas",
LOG_RESOURCE_BUNDLE, "UIMA_continuing_after_exception__FINE", e);
}
}
if (outputCas != null) // new CASes are output
{
// when pushing the stack frame so we know where to pick up later,
// be sure to include the incomplete ParallelStep
if (!destinations.isEmpty()) {
casIteratorStack.push(new StackFrame(casIter, cas, flow, nextAeKey,
new ParallelStep(destinations)));
} else {
casIteratorStack.push(new StackFrame(casIter, cas, flow, nextAeKey));
}
// compute Flow for the output CAS and begin routing it through the flow
flow = flow.newCasProduced(outputCas, nextAeKey);
cas = outputCas;
activeCASes.add(cas);
break; //break out of processing of ParallelStep
} else {
// no new CASes are output; this cas is done being processed
// by that AnalysisEngine so clear the componentInfo
cas.setCurrentComponentInfo(null);
}
} else {
throw new AnalysisEngineProcessException(
AnalysisEngineProcessException.UNKNOWN_ID_IN_SEQUENCE,
new Object[] { nextAeKey });
}
}
} else {
throw new AnalysisEngineProcessException(
AnalysisEngineProcessException.UNSUPPORTED_STEP_TYPE, new Object[] { nextStep
.getClass() });
}
nextStep = flow.next();
}
// FinalStep was returned from FlowController.
// We're done with the CAS.
assert (nextStep instanceof FinalStep);
FinalStep finalStep = (FinalStep) nextStep;
activeCASes.remove(cas);
// If this is the input CAS, just return null to indicate we're done
// processing it. It is an error if the FlowController tried to drop this CAS.
if (cas == mInputCas) {
if (finalStep.getForceCasToBeDropped()) {
throw new AnalysisEngineProcessException(
AnalysisEngineProcessException.ILLEGAL_DROP_CAS, new Object[0]);
}
return null;
}
// Otherwise, this is a new CAS produced within this Aggregate. We may or
// may not return it, depending on the setting of the outputsNewCASes operational
// property in this AE's metadata, and on the value of FinalStep.forceCasToBeDropped
if (mOutputNewCASes && !finalStep.getForceCasToBeDropped()) {
return cas;
} else {
cas.release();
}
}
} catch (Exception e) {
//notify Flow that processing has aborted on this CAS
if (flow != null) {
flow.aborted();
}
release(); // release held CASes before throwing exception
if (e instanceof AnalysisEngineProcessException) {
throw (AnalysisEngineProcessException) e;
} else {
throw new AnalysisEngineProcessException(e);
}
}
}