blob: f27f15857aa5f1feb063133b267d4aa3df098405 [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.action;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.apache.uima.analysis_engine.AnalysisEngine;
import org.apache.uima.analysis_engine.AnalysisEngineProcessException;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.FSIterator;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.FeatureStructure;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.jcas.tcas.Annotation;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.ruta.RutaModule;
import org.apache.uima.ruta.RutaStream;
import org.apache.uima.ruta.ScriptApply;
import org.apache.uima.ruta.block.RutaBlock;
import org.apache.uima.ruta.rule.MatchContext;
import org.apache.uima.ruta.rule.RuleElement;
import org.apache.uima.ruta.rule.RuleMatch;
import org.apache.uima.ruta.type.RutaBasic;
import org.apache.uima.ruta.visitor.InferenceCrowd;
public class CallAction extends AbstractRutaAction {
protected String namespace;
public CallAction(String namespace) {
super();
this.namespace = namespace;
}
@Override
public void execute(MatchContext context, RutaStream stream, InferenceCrowd crowd) {
RuleElement element = context.getElement();
RutaModule thisScript = element.getParent().getScript();
AnalysisEngine targetEngine = thisScript.getEngine(namespace);
if (targetEngine != null) {
try {
callEngine(context, crowd, targetEngine, stream);
} catch (AnalysisEngineProcessException e) {
e.printStackTrace();
} catch (ResourceInitializationException e) {
e.printStackTrace();
}
} else {
RutaBlock block = thisScript.getBlock(namespace);
if (block != null) {
callScript(block, context, stream, crowd);
} else {
if(targetEngine == null) {
throw new IllegalArgumentException("Analysis Engine or Script/Block with name '"+namespace+"' is unknown in script " + context.getParent().getName() + ".");
}
}
}
}
protected void callScript(RutaBlock block, MatchContext context, RutaStream stream,
InferenceCrowd crowd) {
RuleElement element = context.getElement();
RuleMatch match = context.getRuleMatch();
List<AnnotationFS> matchedAnnotationsOf = match.getMatchedAnnotationsOfElement(element);
for (AnnotationFS annotationFS : matchedAnnotationsOf) {
RutaStream windowStream = stream.getWindowStream(annotationFS,
stream.getDocumentAnnotationType());
ScriptApply apply = block.apply(windowStream, crowd);
match.addDelegateApply(this, apply);
}
}
protected void callEngine(MatchContext context, InferenceCrowd crowd,
AnalysisEngine targetEngine, RutaStream stream) throws ResourceInitializationException,
AnalysisEngineProcessException {
RuleElement element = context.getElement();
RuleMatch match = context.getRuleMatch();
List<AnnotationFS> matchedAnnotations = match.getMatchedAnnotations(null,
element.getContainer());
for (AnnotationFS matchedAnnotation : matchedAnnotations) {
StringBuilder newDocument = new StringBuilder();
RutaStream windowStream = stream.getWindowStream(matchedAnnotation,
stream.getDocumentAnnotationType());
windowStream.moveToFirst();
CAS newCAS = targetEngine.newCAS();
List<Type> types = newCAS.getTypeSystem()
.getProperlySubsumedTypes(newCAS.getAnnotationType());
Collection<AnnotationFS> fsToAdd = new HashSet<AnnotationFS>();
Map<Integer, Integer> new2oldBegin = new TreeMap<Integer, Integer>();
Map<Integer, Integer> new2oldEnd = new TreeMap<Integer, Integer>();
Map<Integer, Integer> old2newBegin = new TreeMap<Integer, Integer>();
Map<Integer, Integer> old2newEnd = new TreeMap<Integer, Integer>();
int localBegin = 0;
int localEnd = 0;
while (windowStream.isValid()) {
FeatureStructure fs = windowStream.get();
if (fs instanceof RutaBasic) {
RutaBasic basic = (RutaBasic) fs;
for (Type type : types) {
Collection<AnnotationFS> beginAnchors = basic.getBeginAnchors(type);
for (AnnotationFS a : beginAnchors) {
if (a != null && !a.getType().getName().equals(CAS.TYPE_NAME_DOCUMENT_ANNOTATION)
&& !(a instanceof RutaBasic)) {
fsToAdd.add(a);
}
}
}
int length = basic.getEnd() - basic.getBegin();
localEnd = localBegin + length;
new2oldBegin.put(localBegin, basic.getBegin());
old2newBegin.put(basic.getBegin(), localBegin);
new2oldEnd.put(localEnd, basic.getEnd());
old2newEnd.put(basic.getEnd(), localEnd);
newDocument.append(basic.getCoveredText());
localBegin += length;
}
windowStream.moveToNext();
}
String string = newDocument.toString();
newCAS.setDocumentText(string);
for (AnnotationFS each : fsToAdd) {
int beginOld = each.getBegin();
int endOld = each.getEnd();
Integer beginNew = old2newBegin.get(beginOld);
Integer endNew = old2newEnd.get(endOld);
if (endNew == null && beginNew != null) {
int delta = endOld - beginOld;
endNew = beginNew + delta;
} else if (endNew != null && beginNew == null) {
int delta = endOld - beginOld;
beginNew = endNew - delta;
} else if (endNew == null && beginNew == null) {
int index;
int deltaBefore = 0;
int deltaAfter = 0;
Integer valueBegin = null;
index = beginOld;
while (valueBegin == null) {
valueBegin = new2oldBegin.get(++index);
deltaBefore++;
}
Integer valueEnd = null;
index = endOld;
while (valueEnd == null) {
valueEnd = new2oldEnd.get(--index);
deltaAfter++;
}
beginNew = valueBegin - deltaBefore;
endNew = valueEnd + deltaAfter;
}
String typeName = each.getType().getName();
Type type = newCAS.getTypeSystem().getType(typeName);
FeatureStructure newAnnotation = newCAS.createAnnotation(type, beginNew, endNew);
newCAS.addFsToIndexes(newAnnotation);
}
targetEngine.process(newCAS);
for (Type type : types) {
FSIterator<AnnotationFS> iterator = newCAS.getAnnotationIndex(type).iterator();
while (iterator.isValid()) {
AnnotationFS each = iterator.get();
transform(each, new2oldBegin, new2oldEnd, fsToAdd, stream, match);
iterator.moveToNext();
}
}
}
}
private void transform(FeatureStructure each, Map<Integer, Integer> new2oldBegin,
Map<Integer, Integer> new2oldEnd, Collection<AnnotationFS> fsToAdd, RutaStream stream,
RuleMatch match) {
CAS cas = stream.getCas();
Type newType = cas.getTypeSystem().getType(each.getType().getName());
if (newType != null && !fsToAdd.contains(each)
&& !newType.getName().equals(CAS.TYPE_NAME_DOCUMENT_ANNOTATION)
&& !(each instanceof RutaBasic)) {
FeatureStructure newFS = null;
if (each instanceof AnnotationFS) {
newFS = transformAnnotation((AnnotationFS) each, newType, new2oldBegin, new2oldEnd, stream,
match);
} else {
newFS = cas.createFS(newType);
fillFeatures(each, newFS, newFS.getType(), new2oldBegin, new2oldEnd, stream, match);
}
cas.addFsToIndexes(newFS);
}
}
private FeatureStructure transformAnnotation(AnnotationFS annotation, Type newType,
Map<Integer, Integer> new2oldBegin, Map<Integer, Integer> new2oldEnd, RutaStream stream,
RuleMatch match) {
CAS cas = stream.getCas();
Integer beginOld = annotation.getBegin();
Integer endOld = annotation.getEnd();
FeatureStructure newFS = cas.createFS(newType);
fillFeatures(annotation, newFS, newType, new2oldBegin, new2oldEnd, stream, match);
Integer beginNew = new2oldBegin.get(beginOld);
Integer endNew = new2oldEnd.get(endOld);
if (endNew == null && beginNew != null) {
int delta = endOld - beginOld;
endNew = beginNew + delta;
} else if (endNew != null && beginNew == null) {
int delta = endOld - beginOld;
beginNew = endNew - delta;
} else if (endNew == null && beginNew == null) {
int index;
int deltaBefore = 0;
int deltaAfter = 0;
Integer valueBegin = null;
index = beginOld;
while (valueBegin == null) {
valueBegin = new2oldBegin.get(++index);
deltaBefore++;
}
Integer valueEnd = null;
index = endOld;
while (valueEnd == null) {
valueEnd = new2oldEnd.get(--index);
deltaAfter++;
}
beginNew = valueBegin - deltaBefore;
endNew = valueEnd + deltaAfter;
}
if (newFS instanceof Annotation) {
Annotation newA = (Annotation) newFS;
newA.setBegin(beginNew);
newA.setEnd(endNew);
stream.addAnnotation(newA, match);
}
return newFS;
}
private void fillFeatures(FeatureStructure oldFS, FeatureStructure newFS, Type newType,
Map<Integer, Integer> new2oldBegin, Map<Integer, Integer> new2oldEnd, RutaStream stream,
RuleMatch match) {
for (Object obj : newType.getFeatures()) {
Feature feature = (Feature) obj;
String sn = feature.getShortName();
if (!"sofa".equals(sn) && !"begin".equals(sn) && !"end".equals(sn)) {
Feature oldFeature = oldFS.getType().getFeatureByBaseName(sn);
fillFeature(oldFS, oldFeature, newFS, feature, new2oldBegin, new2oldEnd, stream, match);
}
}
}
private void fillFeature(FeatureStructure oldFS, Feature oldFeature, FeatureStructure newFS,
Feature feature, Map<Integer, Integer> new2oldBegin, Map<Integer, Integer> new2oldEnd,
RutaStream stream, RuleMatch match) {
CAS cas = stream.getCas();
Type oldRange = oldFeature.getRange();
if (oldRange.isPrimitive()) {
if (oldRange.getShortName().equals("String")) {
String stringValue = oldFS.getStringValue(oldFeature);
newFS.setStringValue(feature, stringValue);
} else if (oldRange.getShortName().equals("Integer")) {
Integer intValue = oldFS.getIntValue(oldFeature);
newFS.setIntValue(feature, intValue);
} else if (oldRange.getShortName().equals("Float")) {
Float floatValue = oldFS.getFloatValue(oldFeature);
newFS.setFloatValue(feature, floatValue);
} else if (oldRange.getShortName().equals("Boolean")) {
Boolean booleanValue = oldFS.getBooleanValue(oldFeature);
newFS.setBooleanValue(feature, booleanValue);
}
} else {
FeatureStructure oldFeatureFS = oldFS.getFeatureValue(oldFeature);
FeatureStructure newFeatureFS = null;
if (oldRange.isArray()) {
newFeatureFS = cas.createArrayFS(0);
} else {
newFeatureFS = cas.createFS(feature.getRange());
}
if (newFeatureFS instanceof AnnotationFS) {
transformAnnotation((AnnotationFS) newFeatureFS, newFeatureFS.getType(), new2oldBegin,
new2oldEnd, stream, match);
} else {
fillFeatures(oldFeatureFS, newFeatureFS, newFeatureFS.getType(), new2oldBegin, new2oldEnd,
stream, match);
}
}
}
public String getNamespace() {
return namespace;
}
}