/* | |
* 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; | |
} | |
} |