blob: 0aab776abbba25fa02997e82852e406a91808fdf [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 org.apache.uima.util.Level.SEVERE;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.antlr.runtime.CommonToken;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutableTriple;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.uima.UIMAFramework;
import org.apache.uima.UimaContext;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.CASException;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.cas.text.AnnotationFS;
import org.apache.uima.fit.factory.TypeSystemDescriptionFactory;
import org.apache.uima.fit.internal.ResourceManagerFactory;
import org.apache.uima.resource.ResourceAccessException;
import org.apache.uima.resource.ResourceInitializationException;
import org.apache.uima.resource.ResourceManager;
import org.apache.uima.resource.metadata.TypeDescription;
import org.apache.uima.resource.metadata.TypeSystemDescription;
import org.apache.uima.ruta.action.AbstractRutaAction;
import org.apache.uima.ruta.block.RutaBlock;
import org.apache.uima.ruta.condition.AbstractRutaCondition;
import org.apache.uima.ruta.engine.RutaEngine;
import org.apache.uima.ruta.expression.IRutaExpression;
import org.apache.uima.ruta.expression.annotation.IAnnotationExpression;
import org.apache.uima.ruta.expression.bool.IBooleanExpression;
import org.apache.uima.ruta.expression.bool.SimpleBooleanListExpression;
import org.apache.uima.ruta.expression.list.ListExpression;
import org.apache.uima.ruta.expression.number.INumberExpression;
import org.apache.uima.ruta.expression.number.SimpleNumberListExpression;
import org.apache.uima.ruta.expression.resource.LiteralWordListExpression;
import org.apache.uima.ruta.expression.resource.LiteralWordTableExpression;
import org.apache.uima.ruta.expression.resource.StringWordListExpression;
import org.apache.uima.ruta.expression.resource.StringWordTableExpression;
import org.apache.uima.ruta.expression.resource.WordListExpression;
import org.apache.uima.ruta.expression.resource.WordTableExpression;
import org.apache.uima.ruta.expression.string.IStringExpression;
import org.apache.uima.ruta.expression.string.SimpleStringListExpression;
import org.apache.uima.ruta.expression.type.ITypeExpression;
import org.apache.uima.ruta.expression.type.SimpleTypeExpression;
import org.apache.uima.ruta.expression.type.SimpleTypeListExpression;
import org.apache.uima.ruta.resource.CSVTable;
import org.apache.uima.ruta.resource.MultiTreeWordList;
import org.apache.uima.ruta.resource.RutaResourceLoader;
import org.apache.uima.ruta.resource.RutaTable;
import org.apache.uima.ruta.resource.RutaWordList;
import org.apache.uima.ruta.resource.TreeWordList;
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.verbalize.RutaVerbalizer;
import org.apache.uima.util.InvalidXMLException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
public class RutaEnvironment {
private static final String DOCUMENT = "Document";
private final Object annotationTypeDummy = new Object();
private Map<String, Type> types;
private Map<String, RutaWordList> wordLists;
private Map<String, RutaTable> tables;
private RutaBlock owner;
/**
* Mapping from short type name (e.g. {@code W}) to their disambiguated long type names (e.g.
* {@code org.apache.uima.ruta.type.W}).
*/
private Map<String, String> namespaces;
/**
* Mapping from ambiguous short type names to all their possible long type names.
*/
private Map<String, Set<String>> ambiguousTypeAlias;
/**
* Set of imported typesystems.
*/
private Set<String> typesystems;
/**
* Set of imported scripts.
*/
private Set<String> scripts;
/**
* An alias from a long to a short name.
*/
private static class Alias {
final String longName;
final String shortName;
Alias(String longName, String shortName) {
this.longName = longName;
this.shortName = shortName;
}
}
/**
* Types that are imported in the environment. Keys are type system descriptors and values are
* aliased types.
*/
private Map<String, List<Alias>> typeImports;
/**
* Packages that are imported in the environment without a typesystem specification.
*
* Keys are package names and values are aliases. An empty string as alias means that all types
* from the package should be imported in the default namespace.
*/
private Map<String, List<String>> packageImports;
/**
* Set of types that are declared in the script.
*/
private Set<String> declaredAnnotationTypes;
private Map<String, Object> variableValues;
private Map<String, Object> tempVariableValues;
private Map<String, Class<?>> variableTypes;
private Map<String, Class<?>> availableTypes;
private Map<String, Class<?>> variableGenericTypes;
private Map<String, Class<?>> availableListTypes;
private Map<String, Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>>> macroConditions;
private Map<String, Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>>> macroActions;
private String[] resourcePaths = null;
private CAS cas;
private Map<String, Object> initializedVariables;
private ResourceManager resourceManager;
private Map<String, String> variableAliases;
private RutaVerbalizer verbalizer = new RutaVerbalizer();
public RutaEnvironment(RutaBlock owner) {
super();
this.owner = owner;
types = new HashMap<>();
namespaces = new HashMap<>();
ambiguousTypeAlias = new HashMap<>();
typesystems = new HashSet<>();
scripts = new HashSet<>();
typeImports = new HashMap<>();
packageImports = new HashMap<>();
declaredAnnotationTypes = new HashSet<>();
wordLists = new HashMap<>();
tables = new HashMap<>();
variableValues = new HashMap<>();
tempVariableValues = new HashMap<>();
variableTypes = new HashMap<>();
variableGenericTypes = new HashMap<>();
macroConditions = new HashMap<>();
macroActions = new HashMap<>();
availableTypes = new HashMap<>();
availableTypes.put(RutaConstants.RUTA_VARIABLE_ANNOTATION, AnnotationFS.class);
availableTypes.put("INT", Integer.class);
availableTypes.put("STRING", String.class);
availableTypes.put("DOUBLE", Double.class);
availableTypes.put("FLOAT", Float.class);
availableTypes.put("BOOLEAN", Boolean.class);
availableTypes.put("TYPE", Type.class);
availableTypes.put("CONDITION", AbstractRutaCondition.class);
availableTypes.put("ACTION", AbstractRutaAction.class);
availableTypes.put("WORDLIST", RutaWordList.class);
availableTypes.put("WORDTABLE", RutaTable.class);
availableTypes.put(RutaConstants.RUTA_VARIABLE_ANNOTATION_LIST, List.class);
availableTypes.put("BOOLEANLIST", List.class);
availableTypes.put("INTLIST", List.class);
availableTypes.put("DOUBLELIST", List.class);
availableTypes.put("FLOATLIST", List.class);
availableTypes.put("STRINGLIST", List.class);
availableTypes.put(RutaConstants.RUTA_VARIABLE_TYPE_LIST, List.class);
availableListTypes = new HashMap<>();
availableListTypes.put(RutaConstants.RUTA_VARIABLE_ANNOTATION_LIST, AnnotationFS.class);
availableListTypes.put("BOOLEANLIST", Boolean.class);
availableListTypes.put("INTLIST", Integer.class);
availableListTypes.put("DOUBLELIST", Double.class);
availableListTypes.put("FLOATLIST", Float.class);
availableListTypes.put("STRINGLIST", String.class);
availableListTypes.put(RutaConstants.RUTA_VARIABLE_TYPE_LIST, Type.class);
resourcePaths = getResourcePaths();
initializedVariables = new HashMap<>();
variableAliases = new HashMap<>();
// Always import BasicTypeSystem
addTypeSystem("org.apache.uima.ruta.engine.BasicTypeSystem");
}
/**
* Import short type names.
*
* @param cas
* Cas to initialize the types for.
* @param strictImport
* Specify whether all types should be imported (false) or only types
*/
public void initializeTypes(CAS cas, boolean strictImport) {
this.cas = cas;
try {
if (strictImport) {
importDeclaredTypes(cas.getTypeSystem());
importDeclaredTypesystems(cas.getTypeSystem());
importTypeAliases(cas.getTypeSystem());
importPackageAliases(cas.getTypeSystem());
importDeclaredScripts(cas.getTypeSystem());
} else {
// import all types known to the cas
importAllTypes(cas.getTypeSystem());
importTypeAliases(cas.getTypeSystem());
importPackageAliases(cas.getTypeSystem());
}
ambiguousTypeAlias.remove(DOCUMENT);
namespaces.remove(DOCUMENT);
Type documentType = cas.getTypeSystem().getType(CAS.TYPE_NAME_DOCUMENT_ANNOTATION);
addType(DOCUMENT, documentType);
addType(documentType.getShortName(), documentType);
Type annotationType = cas.getJCas().getCasType(org.apache.uima.jcas.tcas.Annotation.type);
addType("Annotation", annotationType);
} catch (CASException e) {
UIMAFramework.getLogger(getClass()).log(SEVERE, "Cannot initialize types.", e);
} catch (InvalidXMLException e) {
UIMAFramework.getLogger(getClass()).log(SEVERE, "Cannot initialize types.", e);
}
}
/**
* Imports all types that are known to a type system.
*
* @param ts
* Type system to import.
* @throws CASException
*/
private void importAllTypes(TypeSystem ts) throws CASException {
Type topType = ts.getTopType();
if (topType != null) {
List<Type> list = ts.getProperlySubsumedTypes(topType);
for (Type type : list) {
addType(type);
}
}
}
/**
* Import all types that are declared by the script.
*
* @param casTS
* Type system containing all known types.
* @throws InvalidXMLException
* When import cannot be resolved.
*/
private void importDeclaredTypes(TypeSystem casTS) throws InvalidXMLException {
for (String name : declaredAnnotationTypes) {
Type type = casTS.getType(name);
if (type != null) {
addType(type);
} else {
throw new RuntimeException("Type '" + name + "' not found");
}
}
}
/**
* Import all typesystems that are imported in the script.
*
* @param casTS
* Type system containing all known types.
* @throws InvalidXMLException
* When import cannot be resolved.
*/
private void importDeclaredTypesystems(TypeSystem casTS) throws InvalidXMLException {
String[] descriptors = typesystems.toArray(new String[typesystems.size()]);
TypeSystemDescription ts = TypeSystemDescriptionFactory
.createTypeSystemDescription(descriptors);
ts.resolveImports(getResourceManager());
for (TypeDescription td : ts.getTypes()) {
Type type = casTS.getType(td.getName());
if (type != null) {
addType(type);
} else {
throw new RuntimeException("Type '" + td.getName() + "' not found");
}
}
}
/**
* Import all already initialized types of imported scripts.
*
* @param casTS
* Type system containing all known types.
* @throws InvalidXMLException
* When import cannot be resolved.
*/
private void importDeclaredScripts(TypeSystem casTS) throws InvalidXMLException {
RutaModule script = owner.getScript();
for (String eachImportedScript : scripts) {
RutaModule importedModule = script.getScript(eachImportedScript);
RutaEnvironment importedEnvironment = importedModule.getRootBlock().getEnvironment();
Map<String, Type> importedTypeMap = importedEnvironment.getTypes();
Map<String, String> importedNamespaces = importedEnvironment.getNamespaces();
Set<Entry<String, String>> entrySet = importedNamespaces.entrySet();
for (Entry<String, String> entry : entrySet) {
if (!ownsType(entry.getValue()) && !StringUtils.equals(entry.getKey(), DOCUMENT)) {
Type type = importedTypeMap.get(entry.getValue());
addType(entry.getKey(), type);
}
}
// TODO import also wordlists and variables?
}
}
/**
* Imports all type aliases.
*
* @param casTS
* Cas type system.
*/
private void importTypeAliases(TypeSystem casTS) {
for (List<Alias> aliases : typeImports.values()) {
for (Alias alias : aliases) {
Type type = casTS.getType(alias.longName);
if (type == null) {
throw new RuntimeException("Type '" + alias.longName + "' not found");
}
addType(alias.shortName, casTS.getType(alias.longName));
}
}
}
/**
* Import all packages that are imported by the script.
*
* @param casTS
* Type system containing all known types.
*/
private void importPackageAliases(TypeSystem casTS) {
Iterator<Type> iter = casTS.getTypeIterator();
while (iter.hasNext()) {
Type type = iter.next();
String name = type.getName();
String pkg = name.substring(0, Math.max(name.lastIndexOf('.'), 0));
List<String> aliases = packageImports.get(pkg);
if (aliases != null) {
for (String alias : aliases) {
if (alias.isEmpty()) {
addType(type);
} else {
addType(alias + "." + type.getShortName(), type);
}
}
}
}
}
public String[] getResourcePaths() {
if (resourcePaths == null) {
RutaBlock parent = owner.getParent();
if (parent != null) {
return parent.getEnvironment().getResourcePaths();
}
}
return resourcePaths;
}
public void setResourcePaths(String[] resourcePaths) {
this.resourcePaths = resourcePaths;
}
public boolean ownsType(String match) {
match = expand(match);
return types.keySet().contains(match);
}
private String expand(String string) {
String complete = namespaces.get(string);
if (complete == null) {
if (!string.contains(".")) {
complete = namespaces.get(string);
if (complete == null) {
complete = string;
}
} else {
complete = string;
}
}
return complete;
}
/**
* Resolves an annotation type.
*
* @param match
* Annotation type to resolve.
* @return Resolved annotation type or null if match is unknown.
* @throws IllegalArgumentException
* When {@code match} is ambiguous.
*/
public Type getType(String match) {
// make sure that match is not ambiguous
Set<String> ambiguousTargets = ambiguousTypeAlias.get(match);
if (ambiguousTargets != null) {
StringBuilder message = new StringBuilder(match);
message.append(" is ambiguous, use one of the following instead : ");
for (String target : ambiguousTargets) {
message.append(target).append(' ');
}
throw new IllegalArgumentException(message.toString());
}
// try to resolve match
String expanded = expand(match);
Type type = types.get(expanded);
if (type == null) {
RutaBlock parent = owner.getParent();
if (parent != null) {
type = parent.getEnvironment().getType(match);
}
}
return type;
}
public void addType(String string, Type type) {
importType(type.getName(), string);
types.put(type.getName(), type);
}
public void addType(Type type) {
addType(type.getShortName(), type);
}
public void declareType(String name) {
declaredAnnotationTypes.add(name);
}
/**
* Add a typesystem to the script.
*
* @param descriptor
* Type system's descriptor path.
*/
public void addTypeSystem(String descriptor) {
typesystems.add(descriptor);
}
/**
* Add a script to the script.
*
* @param script
* the script's full name.
*/
public void addScript(String script) {
scripts.add(script);
}
/**
* Import a type in the current namespace.
*
* @param longName
* Complete type name.
* @param shortName
* Short type name (without namespace).
*/
private void importType(String longName, String shortName) {
Set<String> targets = ambiguousTypeAlias.get(shortName);
if (targets != null) {
// shortName is already ambiguous, add longName to its list of
// possible targets
targets.add(longName);
} else {
String existing = namespaces.put(shortName, longName);
if (existing != null && !existing.equals(longName)) {
// shortName can now be resolved to "existing" or "longName"
targets = new HashSet<>(2);
targets.add(existing);
targets.add(longName);
// add existing mapping and longName to its list of possible
// targets
ambiguousTypeAlias.put(shortName, targets);
// remove shortName from the namespace because it is ambiguous
namespaces.remove(shortName);
}
}
}
/**
* Import a type from a type system.
*
* @param typesystem
* Typesystem from which to import the type or null.
* @param longName
* Type to import.
* @param shortName
* Short name to use for this type.
*/
public void importTypeFromTypeSystem(String typesystem, String longName, String shortName) {
String key = typesystem != null ? typesystem : "";
List<Alias> aliases = typeImports.get(key);
if (aliases == null) {
aliases = new ArrayList<>();
typeImports.put(key, aliases);
}
aliases.add(new Alias(longName, shortName));
}
/**
* Import a type from a type system.
*
* The type is aliased by its unqualified name.
*
* @param typesystem
* Typesystem from which to import the type or null.
* @param longName
* Type to import.
*/
public void importTypeFromTypeSystem(String typesystem, String longName) {
importTypeFromTypeSystem(typesystem, longName,
longName.substring(longName.lastIndexOf('.') + 1));
}
/**
* Import all the types from a package.
*
* @param typesystem
* Type system describing the package to load.
* @param packageName
* Package to load or null to load all packages.
* @param alias
* Alias of the package. Null or empty string to use no alias.
*/
public void importPackageFromTypeSystem(String typesystem, String packageName, String alias) {
TypeSystemDescription tsd = TypeSystemDescriptionFactory
.createTypeSystemDescription(typesystem);
try {
tsd.resolveImports(getResourceManager());
} catch (InvalidXMLException e) {
throw new RuntimeException("Cannot resolve imports in " + typesystem, e);
}
for (TypeDescription td : tsd.getTypes()) {
String qname = td.getName();
if (packageName == null || (qname.startsWith(packageName)
&& qname.indexOf('.', packageName.length() + 1) == -1)) {
// td is in packageName
if (alias != null) {
String shortName = alias + "." + qname.substring(qname.lastIndexOf('.') + 1);
importTypeFromTypeSystem(typesystem, qname, shortName);
} else {
importTypeFromTypeSystem(typesystem, qname);
}
}
}
}
/**
* Imports all the packages from the specified type system.
*
* @param typesystem
* Typesystem to load.
* @param alias
* Alias for all the packages.
*/
public void importAllPackagesFromTypeSystem(String typesystem, String alias) {
importPackageFromTypeSystem(typesystem, null, alias);
}
/**
* Import all the types from a package that are available at runtime.
*
* @param packageName
* Package to load.
* @param alias
* Alias of the package. Null or empty string to use no alias.
*/
public void importPackage(String packageName, String alias) {
List<String> aliases = packageImports.get(packageName);
if (aliases == null) {
aliases = new ArrayList<>(1);
packageImports.put(packageName, aliases);
}
aliases.add(alias == null ? "" : alias);
}
public RutaWordList getWordList(String list) {
if (list == null) {
return null;
}
RutaWordList result = wordLists.get(list);
UimaContext context = owner.getContext();
Boolean dictRemoveWS = false;
if (context != null) {
dictRemoveWS = (Boolean) context.getConfigParameterValue(RutaEngine.PARAM_DICT_REMOVE_WS);
if (dictRemoveWS == null) {
dictRemoveWS = false;
}
}
if (result == null) {
if (list.endsWith("txt") || list.endsWith("twl") || list.endsWith("mtwl")) {
ResourceLoader resourceLoader = new RutaResourceLoader(getResourcePaths(),
getResourceManager().getExtensionClassLoader());
Resource resource = resourceLoader.getResource(list);
if (resource.exists()) {
try {
if (list.endsWith("mtwl")) {
wordLists.put(list, new MultiTreeWordList(resource));
} else {
wordLists.put(list, new TreeWordList(resource, dictRemoveWS));
}
} catch (IOException e) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
"Error reading word list" + list, e);
}
} else {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Can't find " + list + "!");
}
} else {
try {
RutaWordList rutaList = (RutaWordList) context.getResourceObject(list);
if (rutaList != null) {
wordLists.put(list, rutaList);
} else {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
"Can't find external resource list" + list);
}
} catch (ResourceAccessException e) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
"Can't find external resource list" + list, e);
}
}
}
return wordLists.get(list);
}
public RutaTable getWordTable(String table) {
UimaContext context = owner.getContext();
RutaTable result = tables.get(table);
if (result == null) {
if (table.endsWith("csv") || table.endsWith("txt") || table.endsWith("tsv")) {
ResourceLoader resourceLoader = new RutaResourceLoader(getResourcePaths(),
getResourceManager().getExtensionClassLoader());
Resource resource = resourceLoader.getResource(table);
if (resource.exists()) {
try {
tables.put(table, new CSVTable(resource, getCsvSeparator(context)));
} catch (IOException e) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
"Error reading csv table " + table, e);
}
} else {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
"Can't find " + table + "!");
}
} else {
try {
RutaTable rutaTable = (RutaTable) context.getResourceObject(table);
tables.put(table, rutaTable);
} catch (ResourceAccessException e) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
"Can't find external resource table" + table, e);
}
}
}
return tables.get(table);
}
private String getCsvSeparator(UimaContext context) {
if (context != null) {
String cvsSeparator = (String) context
.getConfigParameterValue(RutaEngine.PARAM_CSV_SEPARATOR);
if (cvsSeparator != null) {
return cvsSeparator;
}
}
return CSVTable.DEFAULT_CSV_SEPARATOR;
}
private void addVariable(String name, Class<?> type, Class<?> generic) {
variableTypes.put(name, type);
if (generic != null) {
variableGenericTypes.put(name, generic);
}
variableValues.put(name, getInitialValue(name, type));
}
@SuppressWarnings("unchecked")
private Object getInitialValue(String name, Class<?> type) {
Object init = initializedVariables.get(name);
if (init != null) {
if (init instanceof List) {
ArrayList<Object> list = new ArrayList<>();
list.addAll((Collection<? extends Object>) init);
return list;
}
return init;
}
if (Integer.class.equals(type)) {
return 0;
} else if (Double.class.equals(type)) {
return 0d;
} else if (Float.class.equals(type)) {
return 0f;
} else if (String.class.equals(type)) {
return null;
} else if (Boolean.class.equals(type)) {
return false;
} else if (Type.class.equals(type)) {
return null;
} else if (List.class.equals(type)) {
return new ArrayList<>();
}
return null;
}
public void addVariable(String name, String type) {
addVariable(name, availableTypes.get(type), availableListTypes.get(type));
}
public void removeVariable(String name) {
variableTypes.remove(name);
variableGenericTypes.remove(name);
variableValues.remove(name);
tempVariableValues.remove(name);
}
public boolean ownsVariable(String name) {
return variableTypes.containsKey(name);
}
public boolean ownsVariableOfType(String name, String type) {
if (variableAliases.containsKey(name)) {
name = variableAliases.get(name);
}
Class<?> varclass = variableTypes.get(name);
Class<?> aclass = availableTypes.get(type);
boolean list = true;
if (aclass.equals(List.class)) {
Class<?> vt = variableGenericTypes.get(name);
Class<?> at = availableListTypes.get(type);
list = vt != null && vt.equals(at);
}
return list && varclass != null && varclass.equals(aclass);
}
public boolean isVariable(String name) {
if (variableAliases.containsKey(name)) {
name = variableAliases.get(name);
}
if (ownsVariable(name)) {
return true;
}
if (owner != null && owner.getParent() != null) {
return owner.getParent().getEnvironment().isVariable(name);
}
return false;
}
public boolean isVariableOfType(String name, String type) {
return ownsVariableOfType(name, type) || (owner.getParent() != null
&& owner.getParent().getEnvironment().isVariableOfType(name, type));
}
public Class<?> getVariableType(String name) {
if (variableAliases.containsKey(name)) {
name = variableAliases.get(name);
}
Class<?> result = variableTypes.get(name);
if (result != null) {
return result;
} else if (owner.getParent() != null) {
return owner.getParent().getEnvironment().getVariableType(name);
}
return null;
}
public Class<?> getVariableGenericType(String name) {
Class<?> result = variableGenericTypes.get(name);
if (result != null) {
return result;
} else if (owner.getParent() != null) {
return owner.getParent().getEnvironment().getVariableGenericType(name);
}
return null;
}
public <T> T getVariableValue(String name, Class<T> type, RutaStream stream) {
if (variableAliases.containsKey(name)) {
name = variableAliases.get(name);
}
Object result = null;
boolean containsKey = variableValues.containsKey(name);
result = tempVariableValues.get(name);
if (result == null) {
result = variableValues.get(name);
}
if (result instanceof String && type.equals(Type.class)) {
// "cast" string to type, because initial values were set when there
// was no cas/type system
// yet
String stringValue = (String) result;
result = types.get(stringValue);
if (result == null) {
// try to resolve short names
result = getType(stringValue);
}
}
if (containsKey && result == null) {
// TODO find the problem with the null values!
// this might now work for word lists in another env.
Object initialValue = getInitialValue(name, type);
if (initialValue instanceof Type) {
return type.cast(initialValue);
} else if (initialValue != null) {
throw new IllegalArgumentException("Variable " + name + " of type " + type
+ " is not correctly initialized! It is not a Type, but " + initialValue);
}
}
if (result == annotationTypeDummy) {
return type.cast(cas.getAnnotationType());
}
if (result != null) {
MatchContext context = new MatchContext(owner);
if (RutaWordList.class.isAssignableFrom(type) && result instanceof WordListExpression) {
WordListExpression wle = (WordListExpression) result;
RutaWordList list = wle.getList(context, stream);
return type.cast(list);
} else if (RutaTable.class.isAssignableFrom(type) && result instanceof WordTableExpression) {
WordTableExpression wte = (WordTableExpression) result;
RutaTable table = wte.getTable(context, stream);
return type.cast(table);
} else {
return type.cast(result);
}
} else if (owner.getParent() != null) {
return owner.getParent().getEnvironment().getVariableValue(name, type, stream);
}
return null;
}
public Object getVariableValue(String name, RutaStream stream) {
return getVariableValue(name, Object.class, stream);
}
@SuppressWarnings("rawtypes")
public Object getLiteralValue(String var, Object value) {
if (ownsVariable(var)) {
MatchContext context = new MatchContext(owner);
Class<?> clazz = variableTypes.get(var);
if (value instanceof INumberExpression) {
INumberExpression ne = (INumberExpression) value;
if (clazz.equals(Integer.class)) {
return ne.getIntegerValue(context, null);
} else if (clazz.equals(Double.class)) {
return ne.getDoubleValue(context, null);
} else if (clazz.equals(Float.class)) {
return ne.getFloatValue(context, null);
} else if (clazz.equals(String.class)) {
return ne.getStringValue(context, null);
}
} else if (clazz.equals(String.class) && value instanceof IStringExpression) {
IStringExpression se = (IStringExpression) value;
return se.getStringValue(context, null);
} else if (clazz.equals(Boolean.class) && value instanceof IBooleanExpression) {
IBooleanExpression be = (IBooleanExpression) value;
return be.getBooleanValue(context, null);
}
if (clazz.equals(RutaWordList.class) && value instanceof LiteralWordListExpression) {
return value;
} else if (clazz.equals(RutaWordList.class) && value instanceof StringWordListExpression) {
return value;
} else if (clazz.equals(RutaWordList.class) && value instanceof String) {
return value;
} else if (clazz.equals(RutaTable.class) && value instanceof LiteralWordTableExpression) {
return value;
} else if (clazz.equals(RutaTable.class) && value instanceof StringWordTableExpression) {
return value;
} else if (clazz.equals(RutaTable.class) && value instanceof String) {
return value;
} else if (clazz.equals(List.class) && value instanceof ListExpression) {
List list = getList((ListExpression) value);
return list;
} else if (clazz.equals(Type.class) && value instanceof CommonToken) {
String typeName = ((CommonToken) value).getText();
return typeName;
} else if (clazz.equals(Type.class) && value instanceof SimpleTypeExpression) {
String typeName = ((SimpleTypeExpression) value).getTypeString();
return typeName;
}
return null;
} else {
return owner.getParent().getEnvironment().getLiteralValue(var, value);
}
}
@SuppressWarnings("unchecked")
public void setInitialVariableValue(String var, Object value) {
if (ownsVariable(var)) {
if (value instanceof List) {
List<Object> initValue = new ArrayList<>();
initValue.addAll((Collection<? extends Object>) value);
initializedVariables.put(var, initValue);
} else {
initializedVariables.put(var, value);
}
setVariableValue(var, value);
} else if (owner.getParent() != null) {
owner.getParent().getEnvironment().setInitialVariableValue(var, value);
}
}
public void setVariableValue(String name, Object value) {
if (variableAliases.containsKey(name)) {
name = variableAliases.get(name);
}
if (ownsVariable(name)) {
Class<?> clazz = variableTypes.get(name);
if (value == null) {
value = getInitialValue(name, clazz);
}
variableValues.put(name, value);
} else if (owner.getParent() != null) {
owner.getParent().getEnvironment().setVariableValue(name, value);
}
}
public void setTempVariableValue(String name, Object value) {
if (variableAliases.containsKey(name)) {
name = variableAliases.get(name);
}
tempVariableValues.put(name, value);
}
@SuppressWarnings("rawtypes")
private List getList(ListExpression value) {
if (value instanceof SimpleBooleanListExpression) {
SimpleBooleanListExpression e = (SimpleBooleanListExpression) value;
return e.getList();
} else if (value instanceof SimpleNumberListExpression) {
SimpleNumberListExpression e = (SimpleNumberListExpression) value;
return e.getList();
} else if (value instanceof SimpleStringListExpression) {
SimpleStringListExpression e = (SimpleStringListExpression) value;
return e.getList();
} else if (value instanceof SimpleTypeListExpression) {
SimpleTypeListExpression e = (SimpleTypeListExpression) value;
return e.getList();
}
return null;
}
public void reset(CAS cas) {
this.cas = cas;
Set<Entry<String, Object>> entrySet = variableValues.entrySet();
for (Entry<String, Object> entry : entrySet) {
String key = entry.getKey();
Class<?> variableType = variableTypes.get(key);
Object initialValue = getInitialValue(key, variableTypes.get(key));
if ((!variableType.equals(RutaTable.class) && !variableType.equals(RutaWordList.class))
|| initialValue != null) {
// not for word lists
entry.setValue(initialValue);
}
}
}
public ResourceManager getResourceManager() {
if (resourceManager != null) {
return resourceManager;
} else {
RutaBlock parent = owner.getParent();
if (parent != null) {
return parent.getEnvironment().getResourceManager();
}
}
// at least return default resource manager
try {
resourceManager = ResourceManagerFactory.newResourceManager();
return resourceManager;
} catch (ResourceInitializationException e) {
UIMAFramework.getLogger(getClass()).log(SEVERE,
"Failed to initialize fallback ResourceManager.", e);
}
return UIMAFramework.newDefaultResourceManager();
}
public void setResourceManager(ResourceManager resourceManager) {
this.resourceManager = resourceManager;
}
public void addMacroAction(String name, Map<String, String> def, Set<String> vars,
List<AbstractRutaAction> actions) {
macroActions.put(name, new ImmutableTriple<>(def, actions, vars));
}
public void addMacroCondition(String name, Map<String, String> def, Set<String> vars,
List<AbstractRutaCondition> conditions) {
macroConditions.put(name, new ImmutableTriple<>(def, conditions, vars));
}
public boolean isMacroAction(String name) {
boolean isDefined = macroActions.keySet().contains(name);
if (isDefined) {
return true;
} else if (owner != null && owner.getParent() != null) {
return owner.getParent().getEnvironment().isMacroAction(name);
}
return false;
}
public boolean isMacroCondition(String name) {
boolean isDefined = macroConditions.keySet().contains(name);
if (isDefined) {
return true;
} else if (owner != null && owner.getParent() != null) {
return owner.getParent().getEnvironment().isMacroCondition(name);
}
return false;
}
public Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>> getMacroAction(
String name) {
Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>> definition = macroActions
.get(name);
if (definition != null) {
return definition;
} else if (owner != null && owner.getParent() != null) {
return owner.getParent().getEnvironment().getMacroAction(name);
}
return null;
}
public Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>> getMacroCondition(
String name) {
Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>> definition = macroConditions
.get(name);
if (definition != null) {
return definition;
} else if (owner != null && owner.getParent() != null) {
return owner.getParent().getEnvironment().getMacroCondition(name);
}
return null;
}
public void addAliasVariable(String name, String var) {
variableAliases.put(name, var);
}
public void removeAliasVariable(String name) {
variableAliases.remove(name);
}
public String getVariableNameOfExpression(IRutaExpression expression) {
String verbalize = verbalizer.verbalize(expression);
return verbalize;
}
public Map<String, Type> getTypes() {
return types;
}
public Set<String> getDeclaredAnnotationTypes() {
return declaredAnnotationTypes;
}
public Set<String> getTypesystems() {
return typesystems;
}
public Map<String, String> getNamespaces() {
return namespaces;
}
public void addMatchToVariable(RuleMatch ruleMatch, RuleElement element, MatchContext context,
RutaStream stream) {
String var = element.getLabel();
if (StringUtils.isBlank(var)) {
return;
}
List<AnnotationFS> annotations = ruleMatch.getMatchedAnnotationsOfElement(element);
addAnnotationsToVariable(annotations, var, context);
}
public void removeVariableValue(String var, MatchContext context) {
if (StringUtils.isBlank(var)) {
return;
}
setTempVariableValue(var, null);
}
public void addAnnotationsToVariable(List<AnnotationFS> annotations, String var,
MatchContext context) {
if (StringUtils.isBlank(var)) {
return;
}
Class<?> variableType = getVariableType(var);
if (List.class.equals(variableType) && AnnotationFS.class.equals(getVariableGenericType(var))) {
setTempVariableValue(var, annotations);
} else if (AnnotationFS.class.equals(variableType)) {
if (context.getDirection()) {
AnnotationFS annotation = null;
if (annotations != null) {
if (context.getDirection()) {
annotation = annotations.get(annotations.size() - 1);
} else {
annotation = annotations.get(0);
}
}
setTempVariableValue(var, annotation);
}
}
}
public void acceptTempVariableValues(Collection<String> localVariables) {
for (String variableName : localVariables) {
if (tempVariableValues.containsKey(variableName)) {
Object value = tempVariableValues.get(variableName);
setVariableValue(variableName, value);
}
}
clearTempVariables(localVariables);
}
public void clearTempVariables(Collection<String> localVariables) {
for (String variableName : localVariables) {
tempVariableValues.remove(variableName);
}
}
public void ensureMaterializedInitialValues(MatchContext matchContext, RutaStream stream) {
for (Entry<String, Object> entry : new ArrayList<>(initializedVariables.entrySet())) {
String var = entry.getKey();
Object value = entry.getValue();
if (value instanceof IAnnotationExpression || value instanceof IBooleanExpression
|| value instanceof INumberExpression || value instanceof IStringExpression
|| value instanceof ITypeExpression) {
Class<?> clazz = variableTypes.get(var);
Object expressionValue = stream.getExpressionValue(clazz, (IRutaExpression) value,
matchContext);
initializedVariables.put(var, expressionValue);
variableValues.put(var, expressionValue);
} else if (value instanceof List) {
List<?> list = (List<?>) value;
List<Object> newList = new ArrayList<>(list.size());
Class<?> clazz = variableGenericTypes.get(var);
for (Object each : list) {
if (each instanceof IAnnotationExpression || each instanceof IBooleanExpression
|| each instanceof INumberExpression || each instanceof IStringExpression
|| each instanceof ITypeExpression) {
Object expressionValue = stream.getExpressionValue(clazz, (IRutaExpression) each,
matchContext);
newList.add(expressionValue);
} else {
newList.add(each);
}
}
initializedVariables.put(var, newList);
variableValues.put(var, new ArrayList<>(newList));
}
}
}
}