blob: e23af6f476f2e7688593f12b04897559bc3633d2 [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.ruta.rule;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.ruta.RutaBlock;
import org.apache.uima.ruta.RutaElement;
import org.apache.uima.ruta.RutaStatement;
import org.apache.uima.ruta.RutaStream;
import org.apache.uima.ruta.ScriptApply;
import org.apache.uima.ruta.action.AbstractRutaAction;
import org.apache.uima.ruta.condition.AbstractRutaCondition;
import org.apache.uima.ruta.rule.quantifier.NormalQuantifier;
import org.apache.uima.ruta.rule.quantifier.RuleElementQuantifier;
import org.apache.uima.ruta.visitor.InferenceCrowd;
public abstract class AbstractRuleElement extends RutaElement implements RuleElement {
protected RuleElementQuantifier quantifier;
protected List<AbstractRutaCondition> conditions;
protected List<AbstractRutaAction> actions;
private boolean startAnchor;
private RuleElementContainer container;
protected RutaBlock parent;
@SuppressWarnings("unchecked")
protected final InferenceCrowd emptyCrowd = new InferenceCrowd(Collections.EMPTY_LIST);
protected List<RutaStatement> inlinedRules;
protected boolean inlineMode;
public AbstractRuleElement(RuleElementQuantifier quantifier,
List<AbstractRutaCondition> conditions, List<AbstractRutaAction> actions,
RuleElementContainer container, RutaBlock parent) {
super();
this.quantifier = quantifier;
this.conditions = conditions;
this.actions = actions;
this.container = container;
this.parent = parent;
if (this.conditions == null) {
this.conditions = new ArrayList<AbstractRutaCondition>();
}
if (this.actions == null) {
this.actions = new ArrayList<AbstractRutaAction>();
}
if (this.quantifier == null) {
this.quantifier = new NormalQuantifier();
}
}
protected void doneMatching(RuleMatch ruleMatch, RuleApply ruleApply, RutaStream stream,
InferenceCrowd crowd) {
if (!ruleMatch.isApplied()) {
ruleApply.add(ruleMatch);
if (ruleMatch.matchedCompletely()) {
ruleMatch.getRule().getRoot().applyRuleElements(ruleMatch, stream, crowd);
}
ruleMatch.setApplied(true);
}
}
protected List<ScriptApply> processInlinedBlockRules(RuleMatch ruleMatch, RutaStream stream,
InferenceCrowd crowd) {
if (inlineMode && inlinedRules != null && !inlinedRules.isEmpty()) {
return processInlinedRules(ruleMatch, stream, crowd);
}
return null;
}
protected List<ScriptApply> processInlinedRules(RuleMatch ruleMatch, RutaStream stream,
InferenceCrowd crowd) {
List<ScriptApply> result = new ArrayList<ScriptApply>();
List<AnnotationFS> matchedAnnotationsOf = ruleMatch.getMatchedAnnotationsOf(this);
// TODO where to implement the explanation of inlined rules?
// BlockApply blockApply = new BlockApply(this);
// RuleApply dummyRuleApply = getDummyRuleApply(ruleMatch);
// blockApply.setRuleApply(dummyRuleApply);
// ruleMatch.addDelegateApply(this, blockApply);
for (AnnotationFS annotationFS : matchedAnnotationsOf) {
RutaStream windowStream = stream.getWindowStream(annotationFS, annotationFS.getType());
for (RutaStatement each : inlinedRules) {
ScriptApply apply = each.apply(windowStream, crowd);
// blockApply.add(apply);
ruleMatch.addDelegateApply(this, apply);
result.add(apply);
}
}
return result;
}
protected List<ScriptApply> processInlinedConditionRules(RuleMatch ruleMatch, RutaStream stream,
InferenceCrowd crowd) {
if (!inlineMode && inlinedRules != null && !inlinedRules.isEmpty()) {
return processInlinedRules(ruleMatch, stream, crowd);
}
return null;
}
public void apply(RuleMatch ruleMatch, RutaStream stream, InferenceCrowd crowd) {
for (AbstractRutaAction action : actions) {
crowd.beginVisit(action, null);
action.execute(ruleMatch, this, stream, crowd);
crowd.endVisit(action, null);
}
processInlinedBlockRules(ruleMatch, stream, crowd);
}
protected boolean matchInnerRules(RuleMatch ruleMatch, RutaStream stream, InferenceCrowd crowd) {
boolean inlinedRulesMatched = true;
List<ScriptApply> list = processInlinedConditionRules(ruleMatch, stream, crowd);
if (list != null) {
inlinedRulesMatched = false;
for (ScriptApply scriptApply : list) {
if (scriptApply instanceof RuleApply) {
RuleApply ra = (RuleApply) scriptApply;
if (ra.applied > 0) {
inlinedRulesMatched = true;
}
}
}
}
return inlinedRulesMatched;
}
protected List<RuleElementMatch> getMatch(RuleMatch ruleMatch,
ComposedRuleElementMatch containerMatch) {
List<RuleElementMatch> matchInfo;
if (containerMatch != null) {
matchInfo = containerMatch.getInnerMatches().get(this);
} else {
matchInfo = ruleMatch.getMatchInfo(this).get(0);
}
return matchInfo;
}
public List<RuleElementMatch> evaluateMatches(List<RuleElementMatch> matches, RutaBlock parent,
RutaStream stream) {
return quantifier.evaluateMatches(matches, parent, stream, emptyCrowd);
}
public List<Integer> getSelfIndexList() {
List<Integer> result = new ArrayList<Integer>(1);
if (getContainer() == null) {
return null;
}
int indexOf = getContainer().getRuleElements().indexOf(this);
result.add(indexOf + 1);
return result;
}
public boolean hasAncestor(boolean after) {
RuleElementContainer c = getContainer();
if (c == null) {
return false;
}
RuleElement nextElement = c.getNextElement(after, this);
if (nextElement != null) {
return true;
}
if (c instanceof ComposedRuleElement) {
return ((ComposedRuleElement) c).hasAncestor(after);
}
return false;
}
protected boolean earlyExit(AnnotationFS eachAnchor, RuleApply ruleApply, RutaStream stream) {
if (stream.isGreedyAnchoring() && ruleApply != null
&& isAlreadyCovered(eachAnchor, ruleApply, stream)) {
// skip if next matched should not overlap
return true;
}
if (stream.isOnlyOnce() && ruleApply != null && ruleApply.getApplied() > 0) {
// skip if the rule should only be applied once, on the first successful match
return true;
}
return false;
}
private boolean isAlreadyCovered(AnnotationFS eachAnchor, RuleApply ruleApply, RutaStream stream) {
List<AbstractRuleMatch<? extends AbstractRule>> list = ruleApply.getList();
Collections.reverse(list);
for (AbstractRuleMatch<? extends AbstractRule> each : list) {
if (each instanceof RuleMatch) {
RuleMatch rm = (RuleMatch) each;
List<AnnotationFS> matchedAnnotationsOf = Collections.emptyList();
if (stream.isGreedyRule()) {
matchedAnnotationsOf = rm.getMatchedAnnotationsOfRoot();
} else if (stream.isGreedyRuleElement()) {
matchedAnnotationsOf = rm.getMatchedAnnotationsOf(this);
}
for (AnnotationFS annotationFS : matchedAnnotationsOf) {
if (eachAnchor.getBegin() >= annotationFS.getBegin()
&& eachAnchor.getEnd() <= annotationFS.getEnd()) {
return true;
} else if (eachAnchor.getBegin() < annotationFS.getEnd()) {
// overlapping annotations of composed rule elements with null ruleApply lookahead
return true;
}
}
}
}
return false;
}
public RuleElementQuantifier getQuantifier() {
return quantifier;
}
public RutaBlock getParent() {
return parent;
}
public List<AbstractRutaCondition> getConditions() {
return conditions;
}
public void setConditions(List<AbstractRutaCondition> conditions) {
this.conditions = conditions;
}
public List<AbstractRutaAction> getActions() {
return actions;
}
public void setActions(List<AbstractRutaAction> actions) {
this.actions = actions;
}
public void setQuantifier(RuleElementQuantifier quantifier) {
this.quantifier = quantifier;
}
public RutaRule getRule() {
return container.getRule();
}
public RuleElementContainer getContainer() {
return container;
}
public void setContainer(RuleElementContainer container) {
this.container = container;
}
public void setStartAnchor(boolean start) {
this.startAnchor = start;
}
public boolean isStartAnchor() {
return startAnchor;
}
public void setInlinedRules(List<RutaStatement> innerRules) {
this.inlinedRules = innerRules;
}
public void setInlineMode(boolean blockMode) {
this.inlineMode = blockMode;
}
public List<RutaStatement> getInlinedRules() {
return inlinedRules;
}
public boolean getInlineMode() {
return inlineMode;
}
}