/* | |
* 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.expression.feature; | |
import static java.util.Arrays.asList; | |
import java.math.BigDecimal; | |
import java.util.Arrays; | |
import java.util.Collection; | |
import java.util.List; | |
import org.apache.uima.cas.ArrayFS; | |
import org.apache.uima.cas.CAS; | |
import org.apache.uima.cas.Feature; | |
import org.apache.uima.cas.FeatureStructure; | |
import org.apache.uima.cas.Type; | |
import org.apache.uima.cas.TypeSystem; | |
import org.apache.uima.cas.text.AnnotationFS; | |
import org.apache.uima.ruta.RutaStream; | |
import org.apache.uima.ruta.expression.IRutaExpression; | |
import org.apache.uima.ruta.expression.MatchReference; | |
import org.apache.uima.ruta.expression.RutaExpression; | |
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.number.INumberExpression; | |
import org.apache.uima.ruta.expression.string.IStringExpression; | |
import org.apache.uima.ruta.expression.type.ITypeExpression; | |
import org.apache.uima.ruta.rule.MatchContext; | |
public class FeatureMatchExpression extends SimpleFeatureExpression { | |
public static final String EQUAL = "=="; | |
public static final String NOT_EQUAL = "!="; | |
private IRutaExpression arg; | |
private String op; | |
public FeatureMatchExpression(MatchReference mr, String op, IRutaExpression arg) { | |
super(mr); | |
this.op = op; | |
this.arg = arg; | |
} | |
public IRutaExpression getArg() { | |
return arg; | |
} | |
public void setArg(RutaExpression arg) { | |
this.arg = arg; | |
} | |
public String getOp() { | |
return op; | |
} | |
public void setOp(String op) { | |
this.op = op; | |
} | |
public boolean checkFeatureValue(FeatureStructure fs, MatchContext context, RutaStream stream) { | |
Feature feature = getFeature(context, stream); | |
if (feature instanceof LazyFeature) { | |
LazyFeature lazyFeature = (LazyFeature) feature; | |
feature = lazyFeature.initialize(fs); | |
} | |
return checkFeatureValue(fs, feature, context, stream); | |
} | |
public boolean checkFeatureValue(FeatureStructure fs, Feature feature, MatchContext context, | |
RutaStream stream) { | |
Type featureRangeType = null; | |
TypeSystem typeSystem = stream.getCas().getTypeSystem(); | |
if (feature instanceof TypeFeature) { | |
if (getArg() instanceof ITypeExpression) { | |
Type t1 = fs.getType(); | |
ITypeExpression expr = (ITypeExpression) getArg(); | |
Type t2 = expr.getType(context, stream); | |
return compare(t1, t2); | |
} | |
} else if (feature instanceof CoveredTextFeature) { | |
featureRangeType = typeSystem.getType(CAS.TYPE_NAME_STRING); | |
} else if (feature != null) { | |
featureRangeType = feature.getRange(); | |
} | |
String rangeName = featureRangeType.getName(); | |
if (rangeName.equals(CAS.TYPE_NAME_BOOLEAN)) { | |
Boolean v1 = fs.getBooleanValue(feature); | |
if (getArg() instanceof IBooleanExpression) { | |
IBooleanExpression expr = (IBooleanExpression) getArg(); | |
Boolean v2 = expr.getBooleanValue(context, stream); | |
return compare(v1, v2); | |
} | |
} else if (rangeName.equals(CAS.TYPE_NAME_INTEGER) || rangeName.equals(CAS.TYPE_NAME_BYTE) | |
|| rangeName.equals(CAS.TYPE_NAME_SHORT) || rangeName.equals(CAS.TYPE_NAME_LONG)) { | |
Integer v1 = fs.getIntValue(feature); | |
if (getArg() instanceof INumberExpression) { | |
INumberExpression expr = (INumberExpression) getArg(); | |
Integer v2 = expr.getIntegerValue(context, stream); | |
return compare(v1, v2); | |
} | |
} else if (rangeName.equals(CAS.TYPE_NAME_DOUBLE)) { | |
Double v1 = fs.getDoubleValue(feature); | |
if (getArg() instanceof INumberExpression) { | |
INumberExpression expr = (INumberExpression) getArg(); | |
Double v2 = expr.getDoubleValue(context, stream); | |
return compare(v1, v2); | |
} | |
} else if (rangeName.equals(CAS.TYPE_NAME_FLOAT)) { | |
Float v1 = fs.getFloatValue(feature); | |
if (getArg() instanceof INumberExpression) { | |
INumberExpression expr = (INumberExpression) getArg(); | |
Float v2 = expr.getFloatValue(context, stream); | |
return compare(v1, v2); | |
} | |
} else if (typeSystem.subsumes(typeSystem.getType(CAS.TYPE_NAME_STRING), featureRangeType)) { | |
String v1 = null; | |
// null is possibly coveredText | |
if (feature instanceof CoveredTextFeature && fs instanceof AnnotationFS) { | |
v1 = ((AnnotationFS) fs).getCoveredText(); | |
} else if (feature != null) { | |
v1 = fs.getStringValue(feature); | |
} | |
if (getArg() instanceof IStringExpression) { | |
IStringExpression expr = (IStringExpression) getArg(); | |
String v2 = expr.getStringValue(context, stream); | |
return compare(v1, v2); | |
} | |
} else { | |
FeatureStructure featureValue = fs.getFeatureValue(feature); | |
if (!feature.getRange().isPrimitive() && getArg() instanceof FeatureExpression) { | |
FeatureExpression fe = (FeatureExpression) getArg(); | |
Collection<? extends FeatureStructure> featureAnnotations = fe | |
.getFeatureStructures(asList(fs), false, context, stream); | |
return compare(featureValue, featureAnnotations); | |
} else if (!feature.getRange().isPrimitive() && getArg() instanceof IAnnotationExpression) { | |
IAnnotationExpression ae = (IAnnotationExpression) getArg(); | |
AnnotationFS compareAnnotation = ae.getAnnotation(context, stream); | |
return compare(featureValue, compareAnnotation); | |
} else if (!feature.getRange().isPrimitive() | |
&& typeSystem.subsumes(typeSystem.getType(CAS.TYPE_NAME_FS_ARRAY), featureRangeType) | |
&& getArg() instanceof IAnnotationListExpression) { | |
ArrayFS<?> fsArray = (ArrayFS<?>) featureValue; | |
IAnnotationListExpression ale = (IAnnotationListExpression) getArg(); | |
List<AnnotationFS> annotationList = ale.getAnnotationList(context, stream); | |
return compare(Arrays.asList(fsArray.toArray()), annotationList); | |
} | |
} | |
return false; | |
} | |
private boolean compare(Object v1, Object v2) { | |
if (v1 == null || v2 == null) { | |
if (v1 == null && v2 == null) { | |
if (getOp().equals("==")) { | |
return true; | |
} else if (getOp().equals("!=")) { | |
return false; | |
} | |
} else { | |
if (getOp().equals("==")) { | |
return false; | |
} else if (getOp().equals("!=")) { | |
return true; | |
} | |
} | |
} else if (v1 instanceof Number && v2 instanceof Number) { | |
Number n1 = (Number) v1; | |
Number n2 = (Number) v2; | |
int compareTo = 0; | |
try { | |
// TODO can throw exception in rule inference!! | |
// TODO replace by something stable and correct | |
compareTo = new BigDecimal(n1.toString()).compareTo(new BigDecimal(n2.toString())); | |
} catch (Exception e) { | |
// TODO: handle exception | |
} | |
if (getOp().equals("==")) { | |
return compareTo == 0; | |
} else if (getOp().equals("!=")) { | |
return compareTo != 0; | |
} else if (getOp().equals(">=")) { | |
return compareTo >= 0; | |
} else if (getOp().equals(">")) { | |
return compareTo > 0; | |
} else if (getOp().equals("<=")) { | |
return compareTo <= 0; | |
} else if (getOp().equals("<")) { | |
return compareTo < 0; | |
} | |
} else if (v1 != null && v2 != null) { | |
if (getOp().equals("==")) { | |
return v1.equals(v2); | |
} else if (getOp().equals("!=")) { | |
return !v1.equals(v2); | |
} | |
} | |
return false; | |
} | |
@Override | |
public String toString() { | |
String result = super.toString(); | |
if (op != null) { | |
result += op; | |
} | |
if (arg != null) { | |
result += arg.toString(); | |
} | |
return result; | |
} | |
} |