blob: 2b49ea59a83f0148f9212ffd2004dfe523344467 [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;
import static java.util.Arrays.asList;
import static java.util.Collections.emptySet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.uima.cas.BooleanArrayFS;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.CASException;
import org.apache.uima.cas.ConstraintFactory;
import org.apache.uima.cas.DoubleArrayFS;
import org.apache.uima.cas.FSIndex;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.FSMatchConstraint;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.FeatureStructure;
import org.apache.uima.cas.FloatArrayFS;
import org.apache.uima.cas.IntArrayFS;
import org.apache.uima.cas.StringArrayFS;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.cas.impl.TypeImpl;
import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.cas.text.AnnotationIndex;
import org.apache.uima.fit.util.CasUtil;
import org.apache.uima.fit.util.FSCollectionFactory;
import org.apache.uima.jcas.JCas;
import org.apache.uima.jcas.tcas.Annotation;
import org.apache.uima.ruta.block.RutaBlock;
import org.apache.uima.ruta.expression.AnnotationTypeExpression;
import org.apache.uima.ruta.expression.IRutaExpression;
import org.apache.uima.ruta.expression.annotation.IAnnotationExpression;
import org.apache.uima.ruta.expression.annotation.IAnnotationListExpression;
import org.apache.uima.ruta.expression.bool.IBooleanExpression;
import org.apache.uima.ruta.expression.bool.IBooleanListExpression;
import org.apache.uima.ruta.expression.feature.CoveredTextFeature;
import org.apache.uima.ruta.expression.feature.FeatureExpression;
import org.apache.uima.ruta.expression.feature.FeatureMatchExpression;
import org.apache.uima.ruta.expression.feature.GenericFeatureExpression;
import org.apache.uima.ruta.expression.feature.LazyFeature;
import org.apache.uima.ruta.expression.feature.SimpleFeatureExpression;
import org.apache.uima.ruta.expression.feature.TypeFeature;
import org.apache.uima.ruta.expression.number.INumberExpression;
import org.apache.uima.ruta.expression.number.INumberListExpression;
import org.apache.uima.ruta.expression.string.IStringExpression;
import org.apache.uima.ruta.expression.string.IStringListExpression;
import org.apache.uima.ruta.expression.type.ITypeExpression;
import org.apache.uima.ruta.expression.type.ITypeListExpression;
import org.apache.uima.ruta.rule.AbstractRule;
import org.apache.uima.ruta.rule.AbstractRuleMatch;
import org.apache.uima.ruta.rule.MatchContext;
import org.apache.uima.ruta.type.RutaAnnotation;
import org.apache.uima.ruta.type.RutaBasic;
import org.apache.uima.ruta.type.RutaOptional;
import org.apache.uima.ruta.utils.RutaListUtils;
import org.apache.uima.ruta.utils.UIMAUtils;
import org.apache.uima.ruta.visitor.InferenceCrowd;
public class RutaStream {
private final CAS cas;
private FSIterator<AnnotationFS> basicIt;
private FSIterator<AnnotationFS> currentIt;
private AnnotationFS documentAnnotation;
private Type documentAnnotationType;
private Type basicType;
private NavigableMap<Integer, RutaBasic> beginAnchors = new TreeMap<>();
private NavigableMap<Integer, RutaBasic> endAnchors = new TreeMap<>();
private FilterManager filter;
private boolean dynamicAnchoring;
private double indexPenalty = 0;
private double anchoringFactor;
private boolean lowMemoryProfile;
private boolean simpleGreedyForComposed;
private InferenceCrowd crowd;
private TypeUsageInformation typeUsage;
private Boolean greedyRuleElement;
private Boolean greedyRule;
private boolean onlyOnce = false;
private Annotation documentBeginAnchor;
private Annotation documentEndAnchor;
private boolean emptyIsInvisible;
private long maxRuleMatches;
private long maxRuleElementMatches;
public RutaStream(CAS cas, Type basicType, FilterManager filter, boolean lowMemoryProfile,
boolean simpleGreedyForComposed, boolean emptyIsInvisible, TypeUsageInformation typeUsage,
InferenceCrowd crowd) {
super();
this.cas = cas;
this.filter = filter;
this.basicType = basicType;
this.lowMemoryProfile = lowMemoryProfile;
this.simpleGreedyForComposed = simpleGreedyForComposed;
this.emptyIsInvisible = emptyIsInvisible;
this.typeUsage = typeUsage;
this.crowd = crowd;
AnnotationFS additionalWindow = filter.getWindowAnnotation();
updateIterators(cas, basicType, filter, additionalWindow);
// really an if? sub it of basic should fix this
if (additionalWindow == null) {
documentAnnotation = cas.getDocumentAnnotation();
documentAnnotationType = getCas().getDocumentAnnotation().getType();
basicIt.moveToFirst();
documentBeginAnchor = new RutaOptional(getJCas(), 0, 0);
documentEndAnchor = new RutaOptional(getJCas(), documentAnnotation.getEnd(),
documentAnnotation.getEnd());
} else {
documentAnnotation = additionalWindow;
documentAnnotationType = filter.getWindowType();
}
}
protected RutaStream(CAS cas, Type basicType, NavigableMap<Integer, RutaBasic> beginAnchors,
NavigableMap<Integer, RutaBasic> endAnchors, FilterManager filter,
boolean lowMemoryProfile, boolean simpleGreedyForComposed, boolean emptyIsInvisible,
TypeUsageInformation typeUsage, InferenceCrowd crowd) {
super();
this.cas = cas;
this.beginAnchors = beginAnchors;
this.endAnchors = endAnchors;
this.filter = filter;
this.basicType = basicType;
this.lowMemoryProfile = lowMemoryProfile;
this.simpleGreedyForComposed = simpleGreedyForComposed;
this.emptyIsInvisible = emptyIsInvisible;
this.typeUsage = typeUsage;
this.crowd = crowd;
AnnotationFS additionalWindow = filter.getWindowAnnotation();
updateIterators(cas, basicType, filter, additionalWindow);
// really an if? sub it of basic should fix this
if (additionalWindow == null) {
documentAnnotation = cas.getDocumentAnnotation();
documentAnnotationType = getCas().getDocumentAnnotation().getType();
basicIt.moveToFirst();
} else {
documentAnnotation = additionalWindow;
documentAnnotationType = filter.getWindowType();
}
}
private void updateIterators(AnnotationFS additionalWindow) {
updateIterators(cas, basicType, filter, additionalWindow);
}
private void updateIterators(CAS cas, Type basicType, FilterManager filter,
AnnotationFS additionalWindow) {
if (additionalWindow != null) {
this.basicIt = cas.getAnnotationIndex(basicType).select().coveredBy(additionalWindow)
.fsIterator();
// was: this.basicIt = cas.getAnnotationIndex(basicType).subiterator(additionalWindow);
} else {
this.basicIt = cas.getAnnotationIndex(basicType).iterator();
}
currentIt = filter.createFilteredIterator(cas, basicType);
}
@Deprecated
public void initalizeBasics(String[] reindexOnly, boolean reindexOnlyMentionedTypes) {
RutaIndexingConfiguration config = new RutaIndexingConfiguration();
config.setReindexOnly(reindexOnly);
config.setReindexOnlyMentionedTypes(reindexOnlyMentionedTypes);
config.setReindexUpdateMode(ReindexUpdateMode.ADDITIVE);
initalizeBasics(config);
}
public void initalizeBasics(RutaIndexingConfiguration config) {
AnnotationIndex<AnnotationFS> basicIndex = cas.getAnnotationIndex(basicType);
boolean basicsAvailable = basicIndex.size() != 0;
if (config.getReindexUpdateMode() == ReindexUpdateMode.NONE && basicsAvailable) {
// there are already some ruta basics and we do not want to update anything, since we know we
// do not need to. Only set internal maps
initializeInternalAnchorMaps(basicIndex);
return;
}
if (!basicsAvailable) {
// indexing
createBasics(config);
} else {
// reindexing
updateBasics(basicIndex, config);
}
}
private void createBasics(RutaIndexingConfiguration config) {
TypeSystem typeSystem = cas.getTypeSystem();
Collection<Type> indexTypes;
if (config.isIndexOnlyMentionedTypes()) {
indexTypes = convertNamesToTypes(typeUsage.getUsedTypes().toArray(new String[0]), typeSystem);
} else {
indexTypes = convertNamesToTypes(config.getIndexOnly(), typeSystem);
}
Collection<Type> indexSkipTypes = convertNamesToTypes(config.getIndexSkipTypes(), typeSystem);
Collection<Type> indexParentTypes = removeSubsumedTypes(indexTypes, typeSystem);
Collection<Type> allIndexTypes = expandToAllSubtypes(indexTypes, indexSkipTypes, typeSystem);
List<FSIndex<AnnotationFS>> relevantIndexes = getRelevantIndexes(typeSystem, indexParentTypes,
indexSkipTypes);
createBasics(relevantIndexes, allIndexTypes);
}
private void updateBasics(AnnotationIndex<AnnotationFS> basicIndex,
RutaIndexingConfiguration config) {
TypeSystem typeSystem = cas.getTypeSystem();
Collection<Type> reindexTypes;
if (config.isReindexOnlyMentionedTypes()) {
reindexTypes = convertNamesToTypes(typeUsage.getUsedTypes().toArray(new String[0]),
typeSystem);
} else {
reindexTypes = convertNamesToTypes(config.getReindexOnly(), typeSystem);
}
Collection<Type> reindexSkipTypes = convertNamesToTypes(config.getReindexSkipTypes(),
typeSystem);
Collection<Type> reindexParentTypes = removeSubsumedTypes(reindexTypes, typeSystem);
Collection<Type> allReindexTypes = expandToAllSubtypes(reindexTypes, reindexSkipTypes,
typeSystem);
List<FSIndex<AnnotationFS>> relevantIndexes = getRelevantIndexes(typeSystem, reindexParentTypes,
reindexSkipTypes);
updateBasics(basicIndex, relevantIndexes, allReindexTypes, config.getReindexUpdateMode());
}
private List<FSIndex<AnnotationFS>> getRelevantIndexes(TypeSystem typeSystem,
Collection<Type> rootReindexTypeList, Collection<Type> skipTypeList) {
List<FSIndex<AnnotationFS>> relevantIndexes = new ArrayList<>();
for (Type type : rootReindexTypeList) {
if (skipTypeForIndexing(type, skipTypeList, typeSystem)) {
continue;
}
if (StringUtils.equals(type.getName(), CAS.TYPE_NAME_ANNOTATION)) {
relevantIndexes.add(cas.getAnnotationIndex().withSnapshotIterators());
} else {
relevantIndexes.add(cas.getAnnotationIndex(type).withSnapshotIterators());
}
}
return relevantIndexes;
}
private boolean skipTypeForIndexing(Type type, Collection<Type> skipTypeList,
TypeSystem typeSystem) {
// collect no ruta basics
if (typeSystem.subsumes(basicType, type)) {
return true;
}
if (skipTypeList != null) {
if (skipTypeList.contains(type)) {
return true;
} else {
for (Type skipType : skipTypeList) {
if (typeSystem.subsumes(skipType, type)) {
return true;
}
}
}
}
return false;
}
private void createBasics(List<FSIndex<AnnotationFS>> relevantIndexes,
Collection<Type> allIndexTypes) {
List<Integer> anchors = getSortedUniqueAnchors(relevantIndexes);
createBasicsForAnchors(anchors);
// add all annotations
for (FSIndex<AnnotationFS> index : relevantIndexes) {
for (AnnotationFS a : index) {
// consider skipped types
if (allIndexTypes == null || allIndexTypes.contains(a.getType())) {
addAnnotation(a, false, false, null);
}
}
}
updateIterators(documentAnnotation);
}
private void createBasicsForAnchors(List<Integer> anchors) {
if (anchors.size() == 0) {
// empty document
createRutaBasic(0, 0);
} else if (anchors.size() == 1) {
Integer first = anchors.get(0);
createRutaBasic(first, first);
} else {
for (int i = 0; i < anchors.size() - 1; i++) {
Integer first = anchors.get(i);
Integer second = anchors.get(i + 1);
if (first < second) { // not really needed
createRutaBasic(first, second);
}
}
}
}
private List<Integer> getSortedUniqueAnchors(List<FSIndex<AnnotationFS>> relevantIndexes) {
Set<Integer> anchorSet = new HashSet<>();
for (FSIndex<AnnotationFS> annotationIndex : relevantIndexes) {
for (AnnotationFS a : annotationIndex) {
anchorSet.add(a.getBegin());
anchorSet.add(a.getEnd());
}
}
List<Integer> anchors = new ArrayList<>(anchorSet);
Collections.sort(anchors);
return anchors;
}
private void updateBasics(AnnotationIndex<AnnotationFS> basicIndex,
List<FSIndex<AnnotationFS>> relevantIndexes, Collection<Type> allReindexTypes,
ReindexUpdateMode indexUpdateMode) {
initializeInternalAnchorMaps(basicIndex);
updateRutaBasicMemoryProfile(basicIndex);
switch (indexUpdateMode) {
case COMPLETE:
updateBasicsComplete(basicIndex, relevantIndexes, allReindexTypes);
break;
case ADDITIVE:
updateBasicsAdditive(basicIndex, relevantIndexes);
break;
case SAFE_ADDITIVE:
updateBasicsSafeAdditive(basicIndex, relevantIndexes, allReindexTypes);
break;
case NONE:
// do nothing
break;
default:
throw new IllegalArgumentException(
"The given IndexUpdateMode is not supported: " + indexUpdateMode);
}
}
private void updateBasicsComplete(AnnotationIndex<AnnotationFS> basicIndex,
List<FSIndex<AnnotationFS>> relevantIndexes, Collection<Type> completeReindexTypeList) {
// cleanup index info for given types
for (AnnotationFS each : basicIndex) {
RutaBasic rutaBasic = (RutaBasic) each;
for (Type type : completeReindexTypeList) {
int code = ((TypeImpl) type).getCode();
rutaBasic.getPartOf()[code] = 0;
rutaBasic.getBeginMap()[code] = null;
rutaBasic.getEndMap()[code] = null;
}
}
// add all annotations
for (FSIndex<AnnotationFS> index : relevantIndexes) {
for (AnnotationFS a : index) {
// consider skipped types
if (completeReindexTypeList.contains(a.getType())) {
addAnnotation(a, false, false, null);
}
}
}
}
private void updateBasicsAdditive(AnnotationIndex<AnnotationFS> basicIndex,
List<FSIndex<AnnotationFS>> relevantIndexes) {
// adds annotation only if not already known and included
for (FSIndex<AnnotationFS> annotationIndex : relevantIndexes) {
for (AnnotationFS a : annotationIndex) {
Type type = a.getType();
RutaBasic beginAnchor = getBeginAnchor(a.getBegin());
RutaBasic endAnchor = getEndAnchor(a.getEnd());
boolean shouldBeAdded = false;
if (beginAnchor == null || endAnchor == null) {
shouldBeAdded = true;
} else {
Collection<AnnotationFS> set = beginAnchor.getBeginAnchors(type);
if (!set.contains(a)) {
shouldBeAdded = true;
}
}
if (shouldBeAdded) {
addAnnotation(a, false, false, null);
}
}
}
}
private void updateBasicsSafeAdditive(AnnotationIndex<AnnotationFS> basicIndex,
List<FSIndex<AnnotationFS>> relevantIndexes, Collection<Type> completeReindexTypeList) {
// search for removed annotations, and remove them
for (AnnotationFS each : basicIndex) {
RutaBasic rutaBasic = (RutaBasic) each;
for (Type type : completeReindexTypeList) {
// it's sufficient to check begin anchors, end should be consistent
Collection<AnnotationFS> beginAnchors = rutaBasic.getBeginAnchors(type);
Collection<AnnotationFS> toRemove = new ArrayList<>();
for (AnnotationFS annotationAtAnchor : beginAnchors) {
if (!annotationAtAnchor.getCAS().getAnnotationIndex().contains(annotationAtAnchor)) {
// not in index? -> was removed
toRemove.add(annotationAtAnchor);
}
}
toRemove.forEach(a -> removeAnnotation(a));
}
}
updateBasicsAdditive(basicIndex, relevantIndexes);
}
private void initializeInternalAnchorMaps(AnnotationIndex<AnnotationFS> basicIndex) {
for (AnnotationFS e : basicIndex) {
beginAnchors.put(e.getBegin(), (RutaBasic) e);
endAnchors.put(e.getEnd(), (RutaBasic) e);
}
}
private void updateRutaBasicMemoryProfile(AnnotationIndex<AnnotationFS> basicIndex) {
RutaBasic firstBasic = (RutaBasic) basicIndex.iterator().get();
if (firstBasic.isLowMemoryProfile() != lowMemoryProfile) {
for (AnnotationFS each : basicIndex) {
RutaBasic eachBasic = (RutaBasic) each;
eachBasic.setLowMemoryProfile(lowMemoryProfile);
}
}
}
private RutaBasic createRutaBasic(int begin, int end) {
RutaBasic newTMB = new RutaBasic(getJCas(), begin, end);
newTMB.setLowMemoryProfile(lowMemoryProfile);
beginAnchors.put(begin, newTMB);
endAnchors.put(end, newTMB);
cas.addFsToIndexes(newTMB);
return newTMB;
}
public void addAnnotation(AnnotationFS annotation, boolean addToIndex,
AbstractRuleMatch<? extends AbstractRule> creator) {
addAnnotation(annotation, addToIndex, true, creator);
}
public void addAnnotation(AnnotationFS annotation,
AbstractRuleMatch<? extends AbstractRule> creator) {
addAnnotation(annotation, false, true, creator);
}
public void addAnnotation(AnnotationFS annotation, boolean addToIndex, boolean updateInternal,
AbstractRuleMatch<? extends AbstractRule> creator) {
Type type = annotation.getType();
// no internal indexing for basics themselves or for zero-length annotations, exception for
// DocumentAnnotation
if (type.equals(basicType) || (annotation.getBegin() >= annotation.getEnd()
&& !annotation.equals(cas.getDocumentAnnotation()))) {
return;
}
if (indexType(annotation.getType())) {
boolean modified = checkSpan(annotation);
if (modified && updateInternal) {
updateIterators(filter.getWindowAnnotation());
}
RutaBasic beginAnchor = getBeginAnchor(annotation.getBegin());
RutaBasic endAnchor = getEndAnchor(annotation.getEnd());
if (beginAnchor != null) {
beginAnchor.addBegin(annotation, type);
}
if (endAnchor != null) {
endAnchor.addEnd(annotation, type);
}
Collection<RutaBasic> basicAnnotationsInWindow = getAllBasicsInWindow(annotation);
for (RutaBasic basic : basicAnnotationsInWindow) {
basic.addPartOf(type);
}
}
if (addToIndex) {
cas.addFsToIndexes(annotation);
}
crowd.annotationAdded(annotation, creator);
}
private boolean indexType(Type type) {
if (typeUsage != null) {
boolean contains = typeUsage.getUsedTypesWithSubTypes().contains(type.getName());
return contains;
}
return true;
}
private boolean checkSpan(AnnotationFS annotation) {
boolean result = false;
int begin = annotation.getBegin();
int end = annotation.getEnd();
RutaBasic beginAnchor = getBeginAnchor(begin);
RutaBasic endAnchor = getEndAnchor(end);
if (beginAnchor != null && endAnchor != null) {
result = false;
} else {
if (beginAnchor == null) {
result |= checkAnchor(begin);
}
if (endAnchor == null) {
result |= checkAnchor(end);
}
}
return result;
}
private boolean checkAnchor(int anchor) {
Entry<Integer, RutaBasic> floorEntry = endAnchors.floorEntry(anchor);
if (floorEntry == null) {
floorEntry = beginAnchors.floorEntry(anchor);
}
Entry<Integer, RutaBasic> ceilingEntry = endAnchors.ceilingEntry(anchor);
if (floorEntry != null && ceilingEntry != null) {
RutaBasic floor = floorEntry.getValue();
RutaBasic ceiling = ceilingEntry.getValue();
RutaBasic toSplit = null;
if (floor.getEnd() > anchor) {
toSplit = floor;
} else {
toSplit = ceiling;
}
int newEnd = toSplit.getEnd();
if (newEnd == anchor) {
return false;
}
cas.removeFsFromIndexes(toSplit);
toSplit.setEnd(anchor);
RutaBasic newRB = new RutaBasic(getJCas(), anchor, newEnd);
newRB.setLowMemoryProfile(lowMemoryProfile);
newRB.setEndMap(toSplit.getEndMap().clone());
newRB.setPartOf(toSplit.getPartOf().clone());
toSplit.clearEndMap();
cas.addFsToIndexes(toSplit);
cas.addFsToIndexes(newRB);
beginAnchors.put(floor.getBegin(), floor);
beginAnchors.put(newRB.getBegin(), newRB);
beginAnchors.put(ceiling.getBegin(), ceiling);
endAnchors.put(floor.getEnd(), floor);
endAnchors.put(newRB.getEnd(), newRB);
endAnchors.put(ceiling.getEnd(), ceiling);
return true;
} else {
// TODO this should never happen! test it!
}
return false;
}
public void removeAnnotation(AnnotationFS annotationFS) {
removeAnnotation(annotationFS, annotationFS.getType());
}
public void removeAnnotation(AnnotationFS annotation, Type type) {
if (type.getName().equals(CAS.TYPE_NAME_DOCUMENT_ANNOTATION)) {
// do not remove DocumentAnnotation
return;
}
Collection<RutaBasic> basicAnnotationsInWindow = getAllBasicsInWindow(annotation);
for (RutaBasic basic : basicAnnotationsInWindow) {
basic.removePartOf(type);
}
Type parent = type;
RutaBasic beginAnchor = getBeginAnchor(annotation.getBegin());
RutaBasic endAnchor = getEndAnchor(annotation.getEnd());
if (beginAnchor != null) {
beginAnchor.removeBegin(annotation, parent);
}
if (endAnchor != null) {
endAnchor.removeEnd(annotation, parent);
}
if (!(annotation instanceof RutaBasic)) {
cas.removeFsFromIndexes(annotation);
}
}
public FSIterator<AnnotationFS> getFilteredBasicIterator(FSMatchConstraint constraint) {
ConstraintFactory cf = cas.getConstraintFactory();
FSMatchConstraint matchConstraint = cf.and(constraint, filter.getDefaultConstraint());
return cas.createFilteredIterator(basicIt, matchConstraint);
}
public RutaStream getWindowStream(AnnotationFS windowAnnotation, Type windowType) {
if (windowAnnotation.getBegin() == documentAnnotation.getBegin()
&& windowAnnotation.getEnd() == documentAnnotation.getEnd()) {
return this;
}
FilterManager filterManager = new FilterManager(filter.getDefaultFilterTypes(),
filter.getCurrentFilterTypes(), filter.getCurrentRetainTypes(), windowAnnotation,
windowType, emptyIsInvisible, cas);
// NavigableMap<Integer, RutaBasic> newBeginAnchors = beginAnchors.subMap(
// windowAnnotation.getBegin(), true, windowAnnotation.getEnd(), false);
// NavigableMap<Integer, RutaBasic> newEndAnchors =
// endAnchors.subMap(windowAnnotation.getBegin(),
// false, windowAnnotation.getEnd(), true);
RutaStream stream = new RutaStream(cas, basicType, beginAnchors, endAnchors, filterManager,
lowMemoryProfile, simpleGreedyForComposed, emptyIsInvisible, typeUsage, crowd);
stream.setDynamicAnchoring(dynamicAnchoring);
stream.setGreedyRuleElement(greedyRuleElement);
stream.setGreedyRule(greedyRule);
stream.setMaxRuleMatches(maxRuleMatches);
stream.setMaxRuleElementMatches(maxRuleElementMatches);
return stream;
}
public RutaStream copy() {
RutaStream stream = new RutaStream(cas, basicType, beginAnchors, endAnchors, filter,
lowMemoryProfile, simpleGreedyForComposed, emptyIsInvisible, typeUsage, crowd);
stream.setDynamicAnchoring(dynamicAnchoring);
stream.setGreedyRuleElement(greedyRuleElement);
stream.setGreedyRule(greedyRule);
stream.setMaxRuleMatches(maxRuleMatches);
stream.setMaxRuleElementMatches(maxRuleElementMatches);
return stream;
}
public AnnotationFS get() throws NoSuchElementException {
return currentIt.get();
}
public boolean isValid() {
return currentIt.isValid();
}
public void moveTo(FeatureStructure fs) {
try {
currentIt.moveTo(fs);
} catch (Exception e) {
// e.printStackTrace();
}
}
public boolean hasNext() {
return currentIt.hasNext();
}
public AnnotationFS next() {
return currentIt.next();
}
public void moveToFirst() {
currentIt.moveToFirst();
}
public void moveToLast() {
currentIt.moveToLast();
}
public void moveToNext() {
currentIt.moveToNext();
}
public void moveToPrevious() {
currentIt.moveToPrevious();
}
public List<AnnotationFS> getOverappingAnnotations(AnnotationFS window, Type type) {
List<AnnotationFS> result = new ArrayList<>();
AnnotationFS newWindow = cas.createAnnotation(type, window.getBegin(), window.getEnd() - 1);
FSIterator<AnnotationFS> iterator = cas.getAnnotationIndex(type).iterator(newWindow);
if (!iterator.isValid()) {
iterator.moveToLast();
}
while (iterator.isValid()) {
FeatureStructure fs = iterator.get();
if (fs instanceof AnnotationFS) {
AnnotationFS a = (AnnotationFS) fs;
if (a.getEnd() >= window.getEnd() && a.getBegin() <= window.getBegin()) {
result.add(a);
}
}
iterator.moveToPrevious();
}
return result;
}
public List<Annotation> getAnnotationsFollowing(Annotation annotation) {
List<Annotation> result = new ArrayList<>();
moveTo(annotation);
while (currentIt.isValid()) {
currentIt.moveToNext();
if (currentIt.isValid()) {
Annotation nextAnnotation = (Annotation) currentIt.get();
if (nextAnnotation.getBegin() == annotation.getEnd()) {
result.add(nextAnnotation);
} else if (nextAnnotation.getBegin() >= annotation.getEnd()) {
break;
}
}
}
return result;
}
public CAS getCas() {
return cas;
}
public JCas getJCas() {
try {
return cas.getJCas();
} catch (CASException e) {
// e.printStackTrace();
}
return null;
}
public List<AnnotationFS> getAllofType(Type type) {
List<AnnotationFS> result = new ArrayList<>();
FSIterator<AnnotationFS> iterator = cas.getAnnotationIndex(type).iterator();
while (iterator.isValid()) {
FeatureStructure featureStructure = iterator.get();
result.add((AnnotationFS) featureStructure);
iterator.moveToNext();
}
return result;
}
public List<AnnotationFS> getAnnotationsInWindow(AnnotationFS windowAnnotation, Type type) {
if (windowAnnotation == null || type == null) {
return Collections.emptyList();
}
TypeSystem typeSystem = getCas().getTypeSystem();
List<AnnotationFS> result = new ArrayList<>();
if (typeSystem.subsumes(type, windowAnnotation.getType())) {
result.add(windowAnnotation);
}
result.addAll(CasUtil.selectCovered(cas, type, windowAnnotation));
return result;
}
public Collection<RutaBasic> getAllBasicsInWindow(AnnotationFS windowAnnotation) {
if (windowAnnotation.getBegin() >= windowAnnotation.getEnd()) {
return emptySet();
}
RutaBasic beginAnchor = getBeginAnchor(windowAnnotation.getBegin());
if (beginAnchor != null && beginAnchor.getEnd() == windowAnnotation.getEnd()) {
return asList(beginAnchor);
}
if (windowAnnotation.getEnd() == cas.getDocumentAnnotation().getEnd()
&& windowAnnotation.getBegin() == 0) {
return beginAnchors.values();
}
return beginAnchors.subMap(windowAnnotation.getBegin(), true, windowAnnotation.getEnd(), false)
.values();
}
public RutaBasic getBasicNextTo(boolean before, AnnotationFS annotation) {
if (annotation == null) {
return null;
}
if (before) {
RutaBasic pointer = endAnchors.get(annotation.getBegin());
while (pointer != null && pointer.getBegin() >= documentAnnotation.getBegin()) {
if (isVisible(pointer)) {
return pointer;
}
Entry<Integer, RutaBasic> lowerEntry = endAnchors.lowerEntry(pointer.getEnd());
if (lowerEntry != null) {
pointer = lowerEntry.getValue();
} else {
pointer = null;
}
}
} else {
RutaBasic pointer = beginAnchors.get(annotation.getEnd());
while (pointer != null && pointer.getEnd() <= documentAnnotation.getEnd()) {
if (isVisible(pointer)) {
return pointer;
}
Entry<Integer, RutaBasic> higherEntry = beginAnchors.higherEntry(pointer.getBegin());
if (higherEntry != null) {
pointer = higherEntry.getValue();
} else {
pointer = null;
}
}
}
return null;
}
public List<RutaBasic> getBasicsInWindow(AnnotationFS windowAnnotation) {
List<RutaBasic> result = new ArrayList<>();
if (windowAnnotation instanceof RutaBasic) {
result.add((RutaBasic) windowAnnotation);
return result;
}
FSMatchConstraint defaultConstraint = filter.getDefaultConstraint();
FSIterator<AnnotationFS> iterator = cas.createFilteredIterator(
cas.getAnnotationIndex(basicType).select().coveredBy(windowAnnotation).fsIterator(),
defaultConstraint);
// FSIterator<AnnotationFS> iterator = cas.createFilteredIterator(
// cas.getAnnotationIndex(basicType).subiterator(windowAnnotation), defaultConstraint);
while (iterator.isValid()) {
result.add((RutaBasic) iterator.get());
iterator.moveToNext();
}
return result;
}
public RutaBasic getFirstBasicInWindow(AnnotationFS windowAnnotation) {
return getFirstBasicInWindow(windowAnnotation, currentIt);
}
public RutaBasic getFirstBasicInWindow(AnnotationFS windowAnnotation,
FSIterator<AnnotationFS> it) {
if (windowAnnotation instanceof RutaBasic) {
return (RutaBasic) windowAnnotation;
}
it.moveTo(windowAnnotation);
if (it.isValid()) {
return (RutaBasic) it.get();
}
return null;
}
public List<RutaBasic> getAnnotationsOverlappingWindow(AnnotationFS annotation) {
if (annotation != null) {
return getBasicsInWindow(annotation);
} else {
return new ArrayList<>();
}
}
public FSIterator<AnnotationFS> getUnfilteredBasicIterator() {
return basicIt;
}
public FSIterator<AnnotationFS> getCurrentIterator() {
return currentIt;
}
public AnnotationFS getDocumentAnnotation() {
return documentAnnotation;
}
public void retainTypes(List<Type> list) {
filter.retainTypes(list);
currentIt = filter.createFilteredIterator(cas, basicType);
}
public void filterTypes(List<Type> list) {
filter.filterTypes(list);
currentIt = filter.createFilteredIterator(cas, basicType);
}
public void addFilterTypes(List<Type> types) {
filter.addFilterTypes(types);
currentIt = filter.createFilteredIterator(cas, basicType);
}
public void addRetainTypes(List<Type> types) {
filter.addRetainTypes(types);
currentIt = filter.createFilteredIterator(cas, basicType);
}
public void removeFilterTypes(List<Type> types) {
filter.removeFilterTypes(types);
currentIt = filter.createFilteredIterator(cas, basicType);
}
public void removeRetainTypes(List<Type> types) {
filter.removeRetainTypes(types);
currentIt = filter.createFilteredIterator(cas, basicType);
}
public FilterManager getFilter() {
return filter;
}
public RutaBasic getFirstBasicOfAll() {
if (beginAnchors.isEmpty()) {
return null;
}
return beginAnchors.firstEntry().getValue();
}
public RutaBasic getLastBasicOfAll() {
if (endAnchors.isEmpty()) {
return null;
}
return endAnchors.lastEntry().getValue();
}
public Type getDocumentAnnotationType() {
return documentAnnotationType;
}
public RutaBasic getNextBasic2(AnnotationFS previous) {
AnnotationFS pointer = cas.createAnnotation(basicType, previous.getEnd() - 1,
previous.getEnd());
currentIt.moveTo(pointer);
if (currentIt.isValid()) {
RutaBasic basic = (RutaBasic) currentIt.get();
return basic;
}
return null;
}
public long getHistogram(Type type) {
return cas.getAnnotationIndex(type).size();
}
public double getIndexPenalty() {
return indexPenalty;
}
public RutaBasic getEndAnchor(int end) {
return endAnchors.get(end);
}
public RutaBasic getBeginAnchor(int begin) {
return beginAnchors.get(begin);
}
public boolean isDynamicAnchoring() {
return dynamicAnchoring;
}
public void setDynamicAnchoring(boolean dynamicAnchoring) {
this.dynamicAnchoring = dynamicAnchoring;
}
public boolean isGreedyRuleElement() {
return greedyRuleElement;
}
public void setGreedyRuleElement(Boolean greedyAnchoring) {
greedyRuleElement = greedyAnchoring;
}
public boolean isGreedyRule() {
return greedyRule;
}
public void setGreedyRule(Boolean greedyAnchoring) {
greedyRule = greedyAnchoring;
}
public void setIndexPenalty(double indexPenalty) {
this.indexPenalty = indexPenalty;
}
public double getAnchoringFactor() {
return anchoringFactor;
}
public void setAnchoringFactor(double anchoringFactor) {
this.anchoringFactor = anchoringFactor;
}
public boolean isSimpleGreedyForComposed() {
return simpleGreedyForComposed;
}
public void setSimpleGreedyForComposed(boolean simpleGreedyForComposed) {
this.simpleGreedyForComposed = simpleGreedyForComposed;
}
public boolean isGreedyAnchoring() {
return greedyRule || greedyRuleElement;
}
public boolean isOnlyOnce() {
return onlyOnce;
}
public void setOnlyOnce(Boolean onlyOnce) {
this.onlyOnce = onlyOnce;
}
public boolean isVisible(AnnotationFS annotationFS) {
return isVisible(annotationFS, false);
}
public boolean isVisible(AnnotationFS annotationFS, boolean ignoreWindow) {
if (annotationFS == null) {
return false;
}
if (annotationFS.getBegin() >= annotationFS.getEnd()) {
return false;
}
AnnotationFS windowAnnotation = filter.getWindowAnnotation();
if (!ignoreWindow && windowAnnotation != null
&& (annotationFS.getBegin() < windowAnnotation.getBegin()
|| annotationFS.getEnd() > windowAnnotation.getEnd())) {
return false;
}
int begin = annotationFS.getBegin();
int end = annotationFS.getEnd();
Set<Type> currentHiddenTypes = filter.getCurrentHiddenTypes();
RutaBasic beginAnchor = getBeginAnchor(begin);
if (beginAnchor != null) {
if (beginAnchor.isEmpty() && emptyIsInvisible) {
return false;
}
for (Type type : currentHiddenTypes) {
boolean partOf = beginAnchor.isPartOf(type);
if (partOf) {
return false;
}
}
}
RutaBasic endAnchor = getEndAnchor(end);
if (endAnchor != null) {
if (endAnchor.isEmpty() && emptyIsInvisible) {
return false;
}
for (Type type : currentHiddenTypes) {
boolean partOf = endAnchor.isPartOf(type);
if (partOf) {
return false;
}
}
}
if (beginAnchor == null && endAnchor == null) {
// missing segmentation in RutaBasics maybe because of temp annotation?
Entry<Integer, RutaBasic> floorEntry = beginAnchors.floorEntry(Integer.valueOf(begin));
Entry<Integer, RutaBasic> ceilingEntry = endAnchors.ceilingEntry(Integer.valueOf(end));
if (floorEntry != null && ceilingEntry != null) {
for (Type type : currentHiddenTypes) {
if (floorEntry.getValue().isPartOf(type) || ceilingEntry.getValue().isPartOf(type)) {
return false;
}
}
}
}
return true;
}
public RutaBasic getAnchor(boolean direction, int pointer) {
if (direction) {
return getBeginAnchor(pointer);
} else {
return getEndAnchor(pointer);
}
}
public RutaBasic getAnchor(boolean direction, AnnotationFS annotation) {
if (direction) {
return getEndAnchor(annotation.getEnd());
} else {
return getBeginAnchor(annotation.getBegin());
}
}
public Collection<AnnotationFS> getAnnotations(Type type) {
Collection<AnnotationFS> result = new LinkedList<>();
AnnotationFS windowAnnotation = filter.getWindowAnnotation();
if (windowAnnotation != null
&& (windowAnnotation.getBegin() != cas.getDocumentAnnotation().getBegin()
|| windowAnnotation.getEnd() != cas.getDocumentAnnotation().getEnd())) {
List<AnnotationFS> selectCovered = CasUtil.selectCovered(cas, type, windowAnnotation);
if (cas.getTypeSystem().subsumes(type, windowAnnotation.getType())) {
if (isVisible(windowAnnotation)) {
result.add(windowAnnotation);
}
}
for (AnnotationFS each : selectCovered) {
if (isVisible(each)) {
result.add(each);
}
}
} else {
AnnotationIndex<AnnotationFS> annotationIndex = cas.getAnnotationIndex(type);
for (AnnotationFS each : annotationIndex) {
if (isVisible(each)) {
result.add(each);
}
}
}
return result;
}
public String getVisibleCoveredText(AnnotationFS annotationFS) {
StringBuilder result = new StringBuilder();
List<RutaBasic> basicsInWindow = getBasicsInWindow(annotationFS);
for (RutaBasic each : basicsInWindow) {
if (isVisible(each)) {
result.append(each.getCoveredText());
}
}
return result.toString();
}
public void assignFeatureValues(FeatureStructure annotation,
Map<IStringExpression, IRutaExpression> map, MatchContext context) {
Type type = annotation.getType();
Set<Entry<IStringExpression, IRutaExpression>> entrySet = map.entrySet();
for (Entry<IStringExpression, IRutaExpression> entry : entrySet) {
IStringExpression key = entry.getKey();
IRutaExpression value = entry.getValue();
String featureName = key.getStringValue(context, this);
Feature feature = type.getFeatureByBaseName(featureName);
if (feature == null) {
throw new IllegalArgumentException("Not able to assign feature value for feature '"
+ featureName + "'. Feature is not defined for type '" + type.getName() + "'"
+ " in script " + context.getParent().getName());
}
assignFeatureValue(annotation, feature, value, context);
}
}
public void assignFeatureValue(FeatureStructure annotation, Feature feature,
IRutaExpression value, MatchContext context) {
if (feature == null || feature instanceof CoveredTextFeature
|| feature instanceof TypeFeature) {
throw new IllegalArgumentException(
"Not able to assign feature value (e.g., coveredText, type) in script "
+ context.getParent().getName());
}
if (feature instanceof LazyFeature) {
LazyFeature lazyFeature = (LazyFeature) feature;
feature = lazyFeature.initialize(annotation);
}
CAS cas = annotation.getCAS();
TypeSystem typeSystem = cas.getTypeSystem();
Type range = feature.getRange();
String rangeName = range.getName();
if (typeSystem.subsumes(typeSystem.getType(CAS.TYPE_NAME_STRING), range)) {
if (value instanceof IStringExpression) {
IStringExpression stringExpr = (IStringExpression) value;
String string = stringExpr.getStringValue(context, this);
annotation.setStringValue(feature, string);
}
} else if (rangeName.equals(CAS.TYPE_NAME_STRING_ARRAY)) {
if (value instanceof IStringListExpression) {
IStringListExpression stringListExpr = (IStringListExpression) value;
List<String> stringList = stringListExpr.getStringList(context, this);
StringArrayFS stringArray = FSCollectionFactory.createStringArrayFS(cas, stringList);
annotation.setFeatureValue(feature, stringArray);
} else if (value instanceof IStringExpression) {
IStringExpression stringExpr = (IStringExpression) value;
String string = stringExpr.getStringValue(context, this);
StringArrayFS array = FSCollectionFactory.createStringArrayFS(cas, new String[] { string });
annotation.setFeatureValue(feature, array);
}
} else if (rangeName.equals(CAS.TYPE_NAME_INTEGER) || rangeName.equals(CAS.TYPE_NAME_LONG)
|| rangeName.equals(CAS.TYPE_NAME_SHORT) || rangeName.equals(CAS.TYPE_NAME_BYTE)) {
if (value instanceof INumberExpression) {
INumberExpression numberExpr = (INumberExpression) value;
int v = numberExpr.getIntegerValue(context, this);
if (annotation instanceof AnnotationFS
&& StringUtils.equals(feature.getShortName(), CAS.FEATURE_BASE_NAME_BEGIN)) {
changeBegin((AnnotationFS) annotation, v, context.getRuleMatch());
} else if (annotation instanceof AnnotationFS
&& StringUtils.equals(feature.getShortName(), CAS.FEATURE_BASE_NAME_END)) {
changeEnd((AnnotationFS) annotation, v, context.getRuleMatch());
} else {
annotation.setIntValue(feature, v);
}
}
} else if (rangeName.equals(CAS.TYPE_NAME_INTEGER_ARRAY)) {
if (value instanceof INumberExpression) {
INumberExpression numberExpr = (INumberExpression) value;
int v = numberExpr.getIntegerValue(context, this);
IntArrayFS array = FSCollectionFactory.createIntArrayFS(cas, new int[] { v });
annotation.setFeatureValue(feature, array);
} else if (value instanceof INumberListExpression) {
INumberListExpression expr = (INumberListExpression) value;
List<Number> list = expr.getNumberList(context, this);
IntArrayFS array = FSCollectionFactory.createIntArrayFS(cas,
RutaListUtils.toIntArray(list));
annotation.setFeatureValue(feature, array);
}
} else if (rangeName.equals(CAS.TYPE_NAME_DOUBLE)) {
if (value instanceof INumberExpression) {
INumberExpression numberExpr = (INumberExpression) value;
double v = numberExpr.getDoubleValue(context, this);
annotation.setDoubleValue(feature, v);
}
} else if (rangeName.equals(CAS.TYPE_NAME_DOUBLE_ARRAY)) {
if (value instanceof INumberExpression) {
INumberExpression numberExpr = (INumberExpression) value;
double v = numberExpr.getDoubleValue(context, this);
DoubleArrayFS array = FSCollectionFactory.createDoubleArrayFS(cas, new double[] { v });
annotation.setFeatureValue(feature, array);
} else if (value instanceof INumberListExpression) {
INumberListExpression expr = (INumberListExpression) value;
List<Number> list = expr.getNumberList(context, this);
DoubleArrayFS array = FSCollectionFactory.createDoubleArrayFS(cas,
RutaListUtils.toDoubleArray(list));
annotation.setFeatureValue(feature, array);
}
} else if (rangeName.equals(CAS.TYPE_NAME_FLOAT)) {
if (value instanceof INumberExpression) {
INumberExpression numberExpr = (INumberExpression) value;
float v = numberExpr.getFloatValue(context, this);
annotation.setFloatValue(feature, v);
}
} else if (rangeName.equals(CAS.TYPE_NAME_FLOAT_ARRAY)) {
if (value instanceof INumberExpression) {
INumberExpression numberExpr = (INumberExpression) value;
float v = numberExpr.getFloatValue(context, this);
FloatArrayFS array = FSCollectionFactory.createFloatArrayFS(cas, new float[] { v });
annotation.setFeatureValue(feature, array);
} else if (value instanceof INumberListExpression) {
INumberListExpression expr = (INumberListExpression) value;
List<Number> list = expr.getNumberList(context, this);
FloatArrayFS array = FSCollectionFactory.createFloatArrayFS(cas,
RutaListUtils.toFloatArray(list));
annotation.setFeatureValue(feature, array);
}
} else if (rangeName.equals(CAS.TYPE_NAME_BOOLEAN)) {
if (value instanceof IBooleanExpression) {
IBooleanExpression expr = (IBooleanExpression) value;
Boolean v = expr.getBooleanValue(context, this);
annotation.setBooleanValue(feature, v);
}
} else if (rangeName.equals(CAS.TYPE_NAME_BOOLEAN_ARRAY)) {
if (value instanceof IBooleanListExpression) {
IBooleanListExpression expr = (IBooleanListExpression) value;
List<Boolean> list = expr.getBooleanList(context, this);
BooleanArrayFS array = FSCollectionFactory.createBooleanArrayFS(cas, list);
annotation.setFeatureValue(feature, array);
} else if (value instanceof IBooleanExpression) {
IBooleanExpression expr = (IBooleanExpression) value;
Boolean v = expr.getBooleanValue(context, this);
BooleanArrayFS array = FSCollectionFactory.createBooleanArrayFS(cas, new boolean[] { v });
annotation.setFeatureValue(feature, array);
}
} else if (value instanceof AnnotationTypeExpression && !range.isPrimitive()) {
AnnotationTypeExpression ate = (AnnotationTypeExpression) value;
if (range.isArray()) {
List<AnnotationFS> annotations = ate.getAnnotationList(context, this);
annotation.setFeatureValue(feature, UIMAUtils.toFSArray(getJCas(), annotations));
} else {
AnnotationFS a = ate.getAnnotation(context, this);
annotation.setFeatureValue(feature, a);
}
} else if (value instanceof IAnnotationExpression && !range.isPrimitive()) {
IAnnotationExpression ae = (IAnnotationExpression) value;
boolean rangeSubsumesAnnotation = cas.getTypeSystem().subsumes(cas.getAnnotationType(),
range);
FeatureStructure a = null;
if (rangeSubsumesAnnotation) {
a = ae.getAnnotation(context, this);
} else {
a = ae.getFeatureStructure(context, this);
}
if (range.isArray()) {
List<FeatureStructure> c = new ArrayList<>();
c.add(a);
annotation.setFeatureValue(feature, UIMAUtils.toFSArray(getJCas(), c));
} else {
annotation.setFeatureValue(feature, a);
}
} else if (value instanceof IAnnotationListExpression && !range.isPrimitive()) {
IAnnotationListExpression ale = (IAnnotationListExpression) value;
List<AnnotationFS> annotations = ale.getAnnotationList(context, this);
if (annotations != null) {
if (range.isArray()) {
annotation.setFeatureValue(feature, UIMAUtils.toFSArray(getJCas(), annotations));
} else {
if (annotations.isEmpty()) {
annotation.setFeatureValue(feature, null);
} else {
annotation.setFeatureValue(feature, annotations.get(0));
}
}
} else {
annotation.setFeatureValue(feature, null);
}
} else if (value instanceof ITypeExpression && !range.isPrimitive()) {
ITypeExpression typeExpr = (ITypeExpression) value;
Type t = typeExpr.getType(context, this);
assignAnnotationByTypeInWindow(annotation, feature, context, t);
} else if (value instanceof GenericFeatureExpression && !range.isPrimitive()) {
FeatureExpression fe = ((GenericFeatureExpression) value).getFeatureExpression();
Type t = fe.getInitialType(context, this);
List<AnnotationFS> inWindow = getAnnotationsInWindow(context.getAnnotation(), t);
if (fe instanceof SimpleFeatureExpression) {
SimpleFeatureExpression sfe = (SimpleFeatureExpression) fe;
List<? extends FeatureStructure> featureAnnotations = null;
if (fe.getFeatures(context, this) != null) {
featureAnnotations = new ArrayList<>(
sfe.getFeatureStructures(inWindow, false, context, this));
} else {
featureAnnotations = inWindow;
}
if (range.isArray()) {
annotation.setFeatureValue(feature, UIMAUtils.toFSArray(getJCas(), featureAnnotations));
} else if (!featureAnnotations.isEmpty()) {
FeatureStructure a = featureAnnotations.get(0);
annotation.setFeatureValue(feature, a);
}
} else {
if (range.isArray()) {
annotation.setFeatureValue(feature, UIMAUtils.toFSArray(getJCas(), inWindow));
} else {
AnnotationFS a = inWindow.get(0);
annotation.setFeatureValue(feature, a);
}
}
}
}
private void assignAnnotationByTypeInWindow(FeatureStructure annotation, Feature feature,
MatchContext context, Type type) {
List<AnnotationFS> inWindow = getAnnotationsInWindow(context.getAnnotation(), type);
if (feature.getRange().isArray()) {
annotation.setFeatureValue(feature, UIMAUtils.toFSArray(getJCas(), inWindow));
} else {
if (inWindow != null && !inWindow.isEmpty()) {
AnnotationFS a = inWindow.get(0);
annotation.setFeatureValue(feature, a);
} else {
annotation.setFeatureValue(feature, null);
}
}
}
public void assignVariable(String var, IRutaExpression expression, MatchContext context) {
RutaBlock parent = context.getParent();
RutaEnvironment environment = parent.getEnvironment();
Class<?> clazz = environment.getVariableType(var);
if (clazz.equals(Double.class) && expression instanceof INumberExpression) {
double v = ((INumberExpression) expression).getDoubleValue(context, this);
environment.setVariableValue(var, v);
} else if (clazz.equals(Float.class) && expression instanceof INumberExpression) {
float v = (float) ((INumberExpression) expression).getDoubleValue(context, this);
environment.setVariableValue(var, v);
} else if (clazz.equals(Integer.class) && expression instanceof INumberExpression) {
int v = ((INumberExpression) expression).getIntegerValue(context, this);
environment.setVariableValue(var, v);
} else if (clazz.equals(Type.class) && expression instanceof ITypeExpression) {
Type v = ((ITypeExpression) expression).getType(context, this);
environment.setVariableValue(var, v);
} else if (clazz.equals(Boolean.class) && expression instanceof IBooleanExpression) {
boolean v = ((IBooleanExpression) expression).getBooleanValue(context, this);
environment.setVariableValue(var, v);
} else if (clazz.equals(String.class) && expression instanceof IStringExpression) {
String v = ((IStringExpression) expression).getStringValue(context, this);
environment.setVariableValue(var, v);
} else if (clazz.equals(AnnotationFS.class) && expression instanceof IAnnotationExpression) {
AnnotationFS v = ((IAnnotationExpression) expression).getAnnotation(context, this);
environment.setVariableValue(var, v);
} else if (clazz.equals(List.class)) {
Class<?> variableGenericType = environment.getVariableGenericType(var);
if (variableGenericType.equals(AnnotationFS.class)
&& expression instanceof IAnnotationListExpression) {
List<AnnotationFS> v = ((IAnnotationListExpression) expression).getAnnotationList(context,
this);
environment.setVariableValue(var, v);
} else if (variableGenericType.equals(Boolean.class)
&& expression instanceof IBooleanListExpression) {
List<Boolean> v = ((IBooleanListExpression) expression).getBooleanList(context, this);
environment.setVariableValue(var, v);
} else if (Number.class.isAssignableFrom(variableGenericType)
&& expression instanceof INumberListExpression) {
List<Number> v = ((INumberListExpression) expression).getNumberList(context, this);
environment.setVariableValue(var, v);
} else if (variableGenericType.equals(String.class)
&& expression instanceof IStringListExpression) {
List<String> v = ((IStringListExpression) expression).getStringList(context, this);
environment.setVariableValue(var, v);
} else if (variableGenericType.equals(Type.class)
&& expression instanceof ITypeListExpression) {
List<Type> v = ((ITypeListExpression) expression).getTypeList(context, this);
environment.setVariableValue(var, v);
}
} else if (clazz.equals(Boolean.class) && expression instanceof AnnotationTypeExpression) {
// special not yet supported use case: b = a1==a2
// TODO: this should be solved by having a boolean expression and an atomic feature
// expression?
AnnotationTypeExpression ate = (AnnotationTypeExpression) expression;
AnnotationFS annotation = ate.getAnnotation(context, this);
FeatureExpression featureExpression = ate.getFeatureExpression();
if (featureExpression instanceof FeatureMatchExpression) {
FeatureMatchExpression fme = (FeatureMatchExpression) featureExpression;
IRutaExpression arg = fme.getArg();
if (arg instanceof IAnnotationExpression) {
AnnotationFS argAnnotation = ((IAnnotationExpression) arg).getAnnotation(context, this);
if (StringUtils.equals(fme.getOp(), "==")) {
environment.setVariableValue(var, annotation == argAnnotation);
} else if (StringUtils.equals(fme.getOp(), "!=")) {
environment.setVariableValue(var, annotation != argAnnotation);
}
}
}
}
}
@SuppressWarnings("unchecked")
public <T extends Object> T getExpressionValue(Class<T> clazz, IRutaExpression expression,
MatchContext context) {
if (clazz.equals(Double.class) && expression instanceof INumberExpression) {
double v = ((INumberExpression) expression).getDoubleValue(context, this);
return (T) Double.valueOf(v);
} else if (clazz.equals(Float.class) && expression instanceof INumberExpression) {
float v = (float) ((INumberExpression) expression).getDoubleValue(context, this);
return (T) Float.valueOf(v);
} else if (clazz.equals(Integer.class) && expression instanceof INumberExpression) {
int v = ((INumberExpression) expression).getIntegerValue(context, this);
return (T) Integer.valueOf(v);
} else if (clazz.equals(Type.class) && expression instanceof ITypeExpression) {
Type v = ((ITypeExpression) expression).getType(context, this);
return (T) v;
} else if (clazz.equals(Boolean.class) && expression instanceof IBooleanExpression) {
boolean v = ((IBooleanExpression) expression).getBooleanValue(context, this);
return (T) Boolean.valueOf(v);
} else if (clazz.equals(String.class) && expression instanceof IStringExpression) {
String v = ((IStringExpression) expression).getStringValue(context, this);
return (T) v;
} else if (clazz.equals(AnnotationFS.class) && expression instanceof IAnnotationExpression) {
AnnotationFS v = ((IAnnotationExpression) expression).getAnnotation(context, this);
return (T) v;
}
return null;
}
public AnnotationFS getSingleAnnotationByTypeInContext(Type type, MatchContext context) {
List<AnnotationFS> inWindow = getAnnotationsInWindow(context.getAnnotation(), type);
if (inWindow != null && !inWindow.isEmpty()) {
return inWindow.get(0);
}
return null;
}
public List<AnnotationFS> getAnnotationsByTypeInContext(Type type, MatchContext context) {
List<AnnotationFS> inWindow = getAnnotationsInWindow(context.getAnnotation(), type);
return inWindow;
}
public List<AnnotationFS> getBestGuessedAnnotationsAt(AnnotationFS window, Type type) {
List<AnnotationFS> result = new ArrayList<>();
if (window == null || type == null) {
return result;
}
TypeSystem typeSystem = getCas().getTypeSystem();
if (typeSystem.subsumes(type, window.getType())) {
result.add(window);
} else {
Collection<AnnotationFS> beginAnchors = getBeginAnchor(window.getBegin())
.getBeginAnchors(type);
Collection<AnnotationFS> endAnchors = getEndAnchor(window.getEnd()).getEndAnchors(type);
@SuppressWarnings("unchecked")
Collection<AnnotationFS> intersection = CollectionUtils.intersection(beginAnchors,
endAnchors);
result.addAll(intersection);
}
return result;
}
public void changeOffsets(AnnotationFS annotation, int begin, int end,
AbstractRuleMatch<? extends AbstractRule> modifikator) {
if (!(annotation instanceof Annotation)) {
return;
}
Annotation a = (Annotation) annotation;
if (annotation.getBegin() == begin && annotation.getEnd() == end) {
return;
}
// TODO implement incremental reindexing
removeAnnotation(a);
a.setBegin(begin);
a.setEnd(end);
addAnnotation(a, true, modifikator);
}
public void changeBegin(AnnotationFS annotation, int begin,
AbstractRuleMatch<? extends AbstractRule> modifikator) {
changeOffsets(annotation, begin, annotation.getEnd(), modifikator);
}
public void changeEnd(AnnotationFS annotation, int end,
AbstractRuleMatch<? extends AbstractRule> modifikator) {
changeOffsets(annotation, annotation.getBegin(), end, modifikator);
}
public AnnotationFS getVeryFirstBeforeWindow(boolean direction) {
if (direction) {
RutaBasic firstBasicOfAll = getFirstBasicOfAll();
int begin = firstBasicOfAll.getBegin();
if (begin == 0) {
return documentBeginAnchor;
} else {
return getEndAnchor(begin);
}
} else {
RutaBasic lastBasicOfAll = getLastBasicOfAll();
int end = lastBasicOfAll.getEnd();
if (end == cas.getDocumentAnnotation().getEnd()) {
return documentEndAnchor;
} else {
return getBeginAnchor(end);
}
}
}
public Type getSharedParentType(List<Type> types) {
if (types == null || types.isEmpty()) {
return cas.getAnnotationType();
}
if (types.size() == 1) {
return types.get(0);
}
TypeSystem typeSystem = cas.getTypeSystem();
Type parentType = types.get(0);
for (Type type : types) {
parentType = getSharedParentType(parentType, type, typeSystem);
}
return parentType;
}
private Type getSharedParentType(Type type1, Type type2, TypeSystem typeSystem) {
if (cas.getAnnotationType().equals(type1) || cas.getAnnotationType().equals(type2)) {
return cas.getAnnotationType();
}
if (type1.equals(type2)) {
return type1;
}
if (typeSystem.subsumes(type1, type2)) {
return type1;
}
if (typeSystem.subsumes(type2, type1)) {
return type2;
}
Type parentType = typeSystem.getParent(type1);
while (parentType != null && !cas.getAnnotationType().equals(parentType)) {
if (typeSystem.subsumes(parentType, type2)) {
return parentType;
}
}
return cas.getAnnotationType();
}
public RutaAnnotation getRutaAnnotationFor(AnnotationFS annotation, boolean create,
RutaStream stream) {
Type heuristicType = cas.getTypeSystem().getType(RutaAnnotation.class.getName());
List<AnnotationFS> ras = CasUtil.selectAt(cas, heuristicType, annotation.getBegin(),
annotation.getEnd());
for (AnnotationFS each : ras) {
if (((RutaAnnotation) each).getAnnotation() == annotation) {
return (RutaAnnotation) each;
}
}
if (create) {
JCas jCas = stream.getJCas();
RutaAnnotation result = new RutaAnnotation(jCas, annotation.getBegin(), annotation.getEnd());
result.setAnnotation((Annotation) annotation);
result.addToIndexes();
return result;
}
return null;
}
private Collection<Type> removeSubsumedTypes(Collection<Type> types, TypeSystem typeSystem) {
List<Type> rootTypes = new ArrayList<>(types);
for (Type type1 : types) {
for (Type type2 : types) {
if (type1 != type2 && typeSystem.subsumes(type1, type2)) {
rootTypes.remove(type2);
}
}
}
return rootTypes;
}
private Collection<Type> expandToAllSubtypes(Collection<Type> reindexTypeList,
Collection<Type> reindexSkipTypes, TypeSystem typeSystem) {
if (reindexTypeList.isEmpty()) {
return Collections.emptyList();
}
Collection<Type> result = new LinkedHashSet<>();
for (Type type : reindexTypeList) {
if (skipTypeForIndexing(type, reindexSkipTypes, typeSystem)) {
continue;
}
result.add(type);
List<Type> properlySubsumedTypes = typeSystem.getProperlySubsumedTypes(type);
for (Type subType : properlySubsumedTypes) {
if (skipTypeForIndexing(subType, reindexSkipTypes, typeSystem)) {
continue;
}
result.add(subType);
}
// if we started with uima.tcas.Annotation, we already collected all
if (type.getName().equals(CAS.TYPE_NAME_ANNOTATION)) {
return result;
}
}
return result;
}
private Collection<Type> convertNamesToTypes(String[] typeNames, TypeSystem typeSystem) {
if (typeNames == null) {
return Collections.emptyList();
}
Collection<Type> result = new ArrayList<>(typeNames.length);
for (String each : typeNames) {
Type type = typeSystem.getType(each);
if (type != null) {
result.add(type);
}
}
return result;
}
public void setMaxRuleMatches(long maxRuleMatches) {
this.maxRuleMatches = maxRuleMatches;
}
public void setMaxRuleElementMatches(long maxRuleElementMatches) {
this.maxRuleElementMatches = maxRuleElementMatches;
}
public long getMaxRuleMatches() {
return maxRuleMatches;
}
public long getMaxRuleElementMatches() {
return maxRuleElementMatches;
}
}