blob: 29bddc94bd17d08eb194c0cbbe9fc3a6756abdff [file] [log] [blame]
/*
* 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.
*/
package org.apache.uima.flow.impl;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import org.apache.uima.UIMAFramework;
import org.apache.uima.UIMARuntimeException;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.analysis_engine.metadata.AnalysisEngineMetaData;
import org.apache.uima.analysis_engine.metadata.FixedFlow;
import org.apache.uima.analysis_engine.metadata.FlowConstraints;
import org.apache.uima.cas.CAS;
import org.apache.uima.flow.CasFlowController_ImplBase;
import org.apache.uima.flow.CasFlow_ImplBase;
import org.apache.uima.flow.FinalStep;
import org.apache.uima.flow.Flow;
import org.apache.uima.flow.FlowControllerContext;
import org.apache.uima.flow.FlowControllerDescription;
import org.apache.uima.flow.SimpleStep;
import org.apache.uima.flow.Step;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.util.InvalidXMLException;
import org.apache.uima.util.XMLInputSource;
/**
* Simple FlowController that invokes components in a fixed sequence.
*/
public class FixedFlowController extends CasFlowController_ImplBase {
/**
* Key for the configuation parameter that determines what should happen to a
* CAS after it has been input to a CAS Multiplier. Possible values are:
* continue: the CAS continues on to the next element in the flow
* stop: the CAS will no longer continue in the flow, and will be returned from the
* aggregate if possible.
* drop: the CAS will no longer continue in the flow, and will be dropped (not
* returned from the aggregate) if possible.
* dropIfNewCasProduced (the default): if the CAS multiplier produced a new CAS as a
* result of processing this CAS, then this CAS will be dropped. If not, then this CAS
* will continue.
*/
public static final String PARAM_ACTION_AFTER_CAS_MULTIPLIER = "ActionAfterCasMultiplier";
private static final int ACTION_CONTINUE = 0;
private static final int ACTION_STOP = 1;
private static final int ACTION_DROP = 2;
private static final int ACTION_DROP_IF_NEW_CAS_PRODUCED = 3;
private ArrayList mSequence;
private int mActionAfterCasMultiplier;
public void initialize(FlowControllerContext aContext) throws ResourceInitializationException {
super.initialize(aContext);
FlowConstraints flowConstraints = aContext.getAggregateMetadata().getFlowConstraints();
mSequence = new ArrayList();
if (flowConstraints instanceof FixedFlow) {
String[] sequence = ((FixedFlow) flowConstraints).getFixedFlow();
mSequence.addAll(Arrays.asList(sequence));
} else {
throw new ResourceInitializationException(ResourceInitializationException.FLOW_CONTROLLER_REQUIRES_FLOW_CONSTRAINTS,
new Object[]{this.getClass().getName(), "fixedFlow", aContext.getAggregateMetadata().getSourceUrlString()});
}
String actionAfterCasMultiplier = (String) aContext
.getConfigParameterValue(PARAM_ACTION_AFTER_CAS_MULTIPLIER);
if ("continue".equalsIgnoreCase(actionAfterCasMultiplier)) {
mActionAfterCasMultiplier = ACTION_CONTINUE;
} else if ("stop".equalsIgnoreCase(actionAfterCasMultiplier)) {
mActionAfterCasMultiplier = ACTION_STOP;
} else if ("drop".equalsIgnoreCase(actionAfterCasMultiplier)) {
mActionAfterCasMultiplier = ACTION_DROP;
} else if ("dropIfNewCasProduced".equalsIgnoreCase(actionAfterCasMultiplier)) {
mActionAfterCasMultiplier = ACTION_DROP_IF_NEW_CAS_PRODUCED;
} else if (actionAfterCasMultiplier == null) {
mActionAfterCasMultiplier = ACTION_DROP_IF_NEW_CAS_PRODUCED; // default
} else {
throw new ResourceInitializationException(ResourceInitializationException.INVALID_ACTION_AFTER_CAS_MULTIPLIER,
new Object[]{actionAfterCasMultiplier});
}
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.flow.CasFlowController_ImplBase#computeFlow(org.apache.uima.cas.CAS)
*/
public Flow computeFlow(CAS aCAS) throws AnalysisEngineProcessException {
return new FixedFlowObject(0);
}
/* (non-Javadoc)
* @see org.apache.uima.flow.FlowController_ImplBase#addAnalysisEngines(java.util.Collection)
*/
public void addAnalysisEngines(Collection aKeys) {
// Append new keys to end of Sequence
mSequence.addAll(aKeys);
}
/* (non-Javadoc)
* @see org.apache.uima.flow.FlowController_ImplBase#removeAnalysisEngines(java.util.Collection)
*/
public void removeAnalysisEngines(Collection aKeys) throws AnalysisEngineProcessException {
//Remove keys from Sequence
mSequence.removeAll(aKeys);
}
public static FlowControllerDescription getDescription() {
URL descUrl = FixedFlowController.class
.getResource("/org/apache/uima/flow/FixedFlowController.xml");
FlowControllerDescription desc;
try {
desc = (FlowControllerDescription) UIMAFramework.getXMLParser().parse(
new XMLInputSource(descUrl));
} catch (InvalidXMLException e) {
throw new UIMARuntimeException(e);
} catch (IOException e) {
throw new UIMARuntimeException(e);
}
return desc;
}
class FixedFlowObject extends CasFlow_ImplBase {
private int currentStep;
private boolean wasPassedToCasMultiplier = false;
private boolean casMultiplierProducedNewCas = false;
private boolean internallyCreatedCas = false;
/**
* Create a new fixed flow starting at step <code>startStep</code> of the fixed sequence.
*
* @param startStep
* index of mSequence to start at
*/
public FixedFlowObject(int startStep) {
this(startStep, false);
}
/**
* Create a new fixed flow starting at step <code>startStep</code> of the fixed sequence.
*
* @param startStep
* index of mSequence to start at
* @param internallyCreatedCas
* true to indicate that this Flow object is for a CAS that was produced by a
* CasMultiplier within this aggregate. Such CASes area allowed to be dropped and not
* output from the aggregate.
*
*/
public FixedFlowObject(int startStep, boolean internallyCreatedCas) {
currentStep = startStep;
this.internallyCreatedCas = internallyCreatedCas;
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.flow.Flow#next()
*/
public Step next() throws AnalysisEngineProcessException {
// if CAS was passed to a CAS multiplier on the last step, special processing
// is needed according to the value of the ActionAfterCasMultiplier config parameter
if (wasPassedToCasMultiplier) {
switch (mActionAfterCasMultiplier) {
case ACTION_STOP:
return new FinalStep();
case ACTION_DROP:
return new FinalStep(internallyCreatedCas);
case ACTION_DROP_IF_NEW_CAS_PRODUCED:
if (casMultiplierProducedNewCas) {
return new FinalStep(internallyCreatedCas);
}
// else, continue with flow
break;
// if action is ACTION_CONTINUE, just continue with flow
}
wasPassedToCasMultiplier = false;
casMultiplierProducedNewCas = false;
}
if (currentStep >= mSequence.size()) {
return new FinalStep(); // this CAS has finished the sequence
}
// if next step is a CasMultiplier, set wasPassedToCasMultiplier to true for next time
// TODO: optimize
AnalysisEngineMetaData md = (AnalysisEngineMetaData) getContext()
.getAnalysisEngineMetaDataMap().get(mSequence.get(currentStep));
if (md.getOperationalProperties().getOutputsNewCASes())
wasPassedToCasMultiplier = true;
// now send the CAS to the next AE in sequence.
return new SimpleStep((String)mSequence.get(currentStep++));
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.flow.CasFlow_ImplBase#newCasProduced(CAS, String)
*/
public Flow newCasProduced(CAS newCas, String producedBy) throws AnalysisEngineProcessException {
// record that the input CAS has been segmented (affects its subsequent flow)
casMultiplierProducedNewCas = true;
// start the new output CAS from the next node after the CasMultiplier that produced it
int i = 0;
while (!mSequence.get(i).equals(producedBy))
i++;
return new FixedFlowObject(i + 1, true);
}
}
}