Author: pkluegl Date: Thu Aug 25 07:01:42 2016 New Revision: 1757611 URL: http://svn.apache.org/viewvc?rev=1757611&view=rev Log: no jira - avoid npe for empty annotation variables in match condition
Modified: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaEnvironment.java Modified: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaEnvironment.java URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaEnvironment.java?rev=1757611&r1=1757610&r2=1757611&view=diff ============================================================================== --- uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaEnvironment.java (original) +++ uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaEnvironment.java Thu Aug 25 07:01:42 2016 @@ -82,979 +82,980 @@ import org.springframework.core.io.Resou public class RutaEnvironment { - private static final String DOCUMENT = "Document"; + private static final String DOCUMENT = "Document"; - private final Object annotationTypeDummy = new Object(); + private final Object annotationTypeDummy = new Object(); - private Map<String, Type> types; + private Map<String, Type> types; - private Map<String, RutaWordList> wordLists; + 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, 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<String, Type>(); - namespaces = new HashMap<String, String>(); - ambiguousTypeAlias = new HashMap<String, Set<String>>(); - typesystems = new HashSet<String>(); - scripts = new HashSet<String>(); - typeImports = new HashMap<String, List<Alias>>(); - packageImports = new HashMap<String, List<String>>(); - declaredAnnotationTypes = new HashSet<String>(); - wordLists = new HashMap<String, RutaWordList>(); - tables = new HashMap<String, RutaTable>(); - variableValues = new HashMap<String, Object>(); - variableTypes = new HashMap<String, Class<?>>(); - variableGenericTypes = new HashMap<String, Class<?>>(); - macroConditions = new HashMap<>(); - macroActions = new HashMap<>(); - availableTypes = new HashMap<String, Class<?>>(); - 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("ANNOTATIONLIST", 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("TYPELIST", List.class); - availableListTypes = new HashMap<String, Class<?>>(); - availableListTypes.put("ANNOTATIONLIST", 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("TYPELIST", Type.class); - resourcePaths = getResourcePaths(); - initializedVariables = new HashMap<String, Object>(); - 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()); - } - - // "Document" can be resolved to "uima.tcas.DocumentAnnotation" or - // "org.apache.uima.ruta.type.Document", - // we force it to the former - ambiguousTypeAlias.remove(DOCUMENT); - namespaces.remove(DOCUMENT); - Type documentType = cas.getTypeSystem().getType(UIMAConstants.TYPE_DOCUMENT); - 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(resourceManager); - 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<String>(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<Alias>(); - 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<String>(1); - packageImports.put(packageName, aliases); - } - - aliases.add(alias == null ? "" : alias); - } - - public RutaWordList getWordList(String list) { - 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()); - 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 rutaTable = (RutaWordList) context.getResourceObject(list); - wordLists.put(list, rutaTable); - } catch (ResourceAccessException e) { - Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, - "Can't find external resource table" + list, e); - } - } - } - - return wordLists.get(list); - } - - public RutaTable getWordTable(String table) { - RutaTable result = tables.get(table); - if (result == null) { - if (table.endsWith("csv")) { - ResourceLoader resourceLoader = new RutaResourceLoader(getResourcePaths()); - Resource resource = resourceLoader.getResource(table); - if (resource.exists()) { - try { - tables.put(table, new CSVTable(resource)); - } 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) owner.getContext().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 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<Object>(); - 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 ""; - } else if (Boolean.class.equals(type)) { - return false; - } else if (Type.class.equals(type)) { - if (cas == null) { - return annotationTypeDummy; - } else { - return cas.getAnnotationType(); - } - } else if (List.class.equals(type)) { - return new ArrayList<Object>(); - } - 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); - } - - 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) { - if (variableAliases.containsKey(name)) { - name = variableAliases.get(name); - } - boolean containsKey = variableValues.containsKey(name); - Object 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 { - throw new IllegalArgumentException("Variable "+name+" of type" +type +" is nto correctly initialized! It is not a Type!"); - } - } - 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); - return type.cast(list); - } else if (RutaTable.class.isAssignableFrom(type) && result instanceof WordTableExpression) { - WordTableExpression wte = (WordTableExpression) result; - RutaTable table = wte.getTable(context); - return type.cast(table); - } else { - return type.cast(result); - } - } else if (owner.getParent() != null) { - return owner.getParent().getEnvironment().getVariableValue(name, type); - } - return null; - } - - public Object getVariableValue(String name) { - return getVariableValue(name, Object.class); - } - - @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 String) { - return value; - } else if (clazz.equals(RutaTable.class) && value instanceof LiteralWordTableExpression) { - 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<Object>(); - 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); - } - } - - @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(); - Object initialValue = getInitialValue(key, variableTypes.get(key)); - if (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 - 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<Map<String, String>, List<AbstractRutaAction>, Set<String>>(def, - actions, vars)); - } - - public void addMacroCondition(String name, Map<String, String> def, Set<String> vars, - List<AbstractRutaCondition> conditions) { - macroConditions.put(name, - new ImmutableTriple<Map<String, String>, List<AbstractRutaCondition>, Set<String>>(def, - conditions, vars)); - } - - public boolean isMacroAction(String name) { - return macroActions.keySet().contains(name); - } - - public boolean isMacroCondition(String name) { - return macroConditions.keySet().contains(name); - } - - public Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>> getMacroAction( - String name) { - return macroActions.get(name); - } - - public Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>> getMacroCondition( - String name) { - return macroConditions.get(name); - } - - 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; - } + 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, 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<String, Type>(); + namespaces = new HashMap<String, String>(); + ambiguousTypeAlias = new HashMap<String, Set<String>>(); + typesystems = new HashSet<String>(); + scripts = new HashSet<String>(); + typeImports = new HashMap<String, List<Alias>>(); + packageImports = new HashMap<String, List<String>>(); + declaredAnnotationTypes = new HashSet<String>(); + wordLists = new HashMap<String, RutaWordList>(); + tables = new HashMap<String, RutaTable>(); + variableValues = new HashMap<String, Object>(); + variableTypes = new HashMap<String, Class<?>>(); + variableGenericTypes = new HashMap<String, Class<?>>(); + macroConditions = new HashMap<>(); + macroActions = new HashMap<>(); + availableTypes = new HashMap<String, Class<?>>(); + 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("ANNOTATIONLIST", 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("TYPELIST", List.class); + availableListTypes = new HashMap<String, Class<?>>(); + availableListTypes.put("ANNOTATIONLIST", 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("TYPELIST", Type.class); + resourcePaths = getResourcePaths(); + initializedVariables = new HashMap<String, Object>(); + 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()); + } + + // "Document" can be resolved to "uima.tcas.DocumentAnnotation" or + // "org.apache.uima.ruta.type.Document", + // we force it to the former + ambiguousTypeAlias.remove(DOCUMENT); + namespaces.remove(DOCUMENT); + Type documentType = cas.getTypeSystem().getType(UIMAConstants.TYPE_DOCUMENT); + 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(resourceManager); + 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<String>(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<Alias>(); + 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<String>(1); + packageImports.put(packageName, aliases); + } + + aliases.add(alias == null ? "" : alias); + } + + public RutaWordList getWordList(String list) { + 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()); + 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 rutaTable = (RutaWordList) context.getResourceObject(list); + wordLists.put(list, rutaTable); + } catch (ResourceAccessException e) { + Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, + "Can't find external resource table" + list, e); + } + } + } + + return wordLists.get(list); + } + + public RutaTable getWordTable(String table) { + RutaTable result = tables.get(table); + if (result == null) { + if (table.endsWith("csv")) { + ResourceLoader resourceLoader = new RutaResourceLoader(getResourcePaths()); + Resource resource = resourceLoader.getResource(table); + if (resource.exists()) { + try { + tables.put(table, new CSVTable(resource)); + } 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) owner.getContext().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 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<Object>(); + 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 ""; + } else if (Boolean.class.equals(type)) { + return false; + } else if (Type.class.equals(type)) { + if (cas == null) { + return annotationTypeDummy; + } else { + return cas.getAnnotationType(); + } + } else if (List.class.equals(type)) { + return new ArrayList<Object>(); + } + 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); + } + + 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) { + if (variableAliases.containsKey(name)) { + name = variableAliases.get(name); + } + boolean containsKey = variableValues.containsKey(name); + Object 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); + return type.cast(list); + } else if (RutaTable.class.isAssignableFrom(type) && result instanceof WordTableExpression) { + WordTableExpression wte = (WordTableExpression) result; + RutaTable table = wte.getTable(context); + return type.cast(table); + } else { + return type.cast(result); + } + } else if (owner.getParent() != null) { + return owner.getParent().getEnvironment().getVariableValue(name, type); + } + return null; + } + + public Object getVariableValue(String name) { + return getVariableValue(name, Object.class); + } + + @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 String) { + return value; + } else if (clazz.equals(RutaTable.class) && value instanceof LiteralWordTableExpression) { + 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<Object>(); + 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); + } + } + + @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(); + Object initialValue = getInitialValue(key, variableTypes.get(key)); + if (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 + 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<Map<String, String>, List<AbstractRutaAction>, Set<String>>(def, actions, vars)); + } + + public void addMacroCondition(String name, Map<String, String> def, Set<String> vars, + List<AbstractRutaCondition> conditions) { + macroConditions.put(name, new ImmutableTriple<Map<String, String>, List<AbstractRutaCondition>, Set<String>>( + def, conditions, vars)); + } + + public boolean isMacroAction(String name) { + return macroActions.keySet().contains(name); + } + + public boolean isMacroCondition(String name) { + return macroConditions.keySet().contains(name); + } + + public Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>> getMacroAction(String name) { + return macroActions.get(name); + } + + public Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>> getMacroCondition(String name) { + return macroConditions.get(name); + } + + 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; + } }