blob: 9fd0fa636b0820d313368e3d82712480e81023d4 [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.analysis_engine.impl;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.apache.uima.analysis_engine.ResultSpecification;
import org.apache.uima.analysis_engine.TypeOrFeature;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.resource.metadata.Capability;
import org.apache.uima.resource.metadata.impl.MetaDataObject_impl;
import org.apache.uima.resource.metadata.impl.PropertyXmlInfo;
import org.apache.uima.resource.metadata.impl.XmlizationInfo;
/**
* Reference implementaion of {@link ResultSpecification}.
*
*
*/
public final class ResultSpecification_impl extends MetaDataObject_impl implements
ResultSpecification {
private static final long serialVersionUID = 8516517600467270594L;
static final String UNSPECIFIED_LANGUAGE = "x-unspecified";
/**
* main language separator e.g 'en' and 'en-US'
*/
private static final char LANGUAGE_SEPARATOR = '-';
/**
* Map from TypeOrFeature objects to HashSets that include the language codes (Strings) for which
* that type or feature should be produced.
*/
private Map mTypesAndFeatures = new HashMap();
/**
* Map from String type or feature names to HashSets that include the language codes (Strings) for
* which that type or feature should be produced. This is populated by the compile() method, and
* includes subtypes as well as the individual feature names for types that have
* allAnnotatorFeatures=true.
*/
private Map mCompiledNameToLanguageMap = new HashMap();
/**
* Default language set to use if nothing else is specified
*/
private HashSet mDefaultLanguage = new HashSet();
/**
* constructor init the default languge set with the language x-unspecified
*/
public ResultSpecification_impl() {
mDefaultLanguage.add(UNSPECIFIED_LANGUAGE);
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#getResultTypesAndFeatures()
*/
public TypeOrFeature[] getResultTypesAndFeatures() {
TypeOrFeature[] arr = new TypeOrFeature[mTypesAndFeatures.size()];
mTypesAndFeatures.keySet().toArray(arr);
return arr;
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#getResultTypesAndFeatures(java.lang.String)
*/
public TypeOrFeature[] getResultTypesAndFeatures(String language) {
// get language without country if applicable
String baseLanguage = null;
int index = language.indexOf(LANGUAGE_SEPARATOR);
if (index > -1) {
baseLanguage = language.substring(0, index);
}
// holds the found ToFs for the specified language
Vector vec = new Vector();
Iterator it = mTypesAndFeatures.keySet().iterator();
while (it.hasNext()) {
// get current key
TypeOrFeature tof = (TypeOrFeature) it.next();
// get value for the current key
Set values = (HashSet) mTypesAndFeatures.get(tof);
if (values.contains(language) || values.contains(UNSPECIFIED_LANGUAGE)
|| values.contains(baseLanguage)) {
// add tof to the TypeOfFeature array
vec.add(tof);
}
}
// create array for return
TypeOrFeature[] arr = new TypeOrFeature[vec.size()];
// convert vector to TypeOrFeature[]
vec.toArray(arr);
return arr;
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#setResultTypesAndFeatures(org.apache.uima.analysis_engine.TypeOrFeature[])
*/
public void setResultTypesAndFeatures(TypeOrFeature[] aTypesAndFeatures) {
mTypesAndFeatures.clear();
for (int i = 0; i < aTypesAndFeatures.length; i++) {
mTypesAndFeatures.put(aTypesAndFeatures[i], mDefaultLanguage);
}
// revert to uncompiled state
mCompiledNameToLanguageMap.clear();
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#setResultTypesAndFeatures(org.apache.uima.analysis_engine.TypeOrFeature[],
* java.lang.String[])
*/
public void setResultTypesAndFeatures(TypeOrFeature[] aTypesAndFeatures, String[] aLanguageIDs) {
if (aLanguageIDs != null) {
// create HashSet for the aLanguageIDs with the initial capacity of the aLanguageIDs size
HashSet languagesSupported = new HashSet(aLanguageIDs.length);
// add all supported languages to at HashSet
for (int x = 0; x < aLanguageIDs.length; x++) {
// add current language to the HashSet
languagesSupported.add(aLanguageIDs[x]);
}
mTypesAndFeatures.clear();
for (int i = 0; i < aTypesAndFeatures.length; i++) {
mTypesAndFeatures.put(aTypesAndFeatures[i], languagesSupported);
}
// revert to uncompiled state
mCompiledNameToLanguageMap.clear();
} else {
// if aLangugeIDs is null set ToFs for the default language
setResultTypesAndFeatures(aTypesAndFeatures);
}
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#addResultTypeOrFeature(org.apache.uima.analysis_engine.TypeOrFeature)
*/
public void addResultTypeOrFeature(TypeOrFeature aTypeOrFeature) {
mTypesAndFeatures.put(aTypeOrFeature, mDefaultLanguage);
// revert to uncompiled state
mCompiledNameToLanguageMap.clear();
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#addResultTypeOrFeature(org.apache.uima.analysis_engine.TypeOrFeature,
* java.lang.String[])
*/
public void addResultTypeOrFeature(TypeOrFeature aTypeOrFeature, String[] aLanguageIDs) {
if (aLanguageIDs != null) {
// create HashSet for the aLanguageIDs with the initial capacity of the aLanguageIDs size
HashSet languagesSupported = new HashSet(aLanguageIDs.length);
// add all supported languages to at HashSet
for (int x = 0; x < aLanguageIDs.length; x++) {
// add current language to the HashSet
languagesSupported.add(aLanguageIDs[x]);
}
mTypesAndFeatures.put(aTypeOrFeature, languagesSupported);
// revert to uncompiled state
mCompiledNameToLanguageMap.clear();
} else {
// if aLangugeIDs is null add ToF with the default language
addResultTypeOrFeature(aTypeOrFeature);
}
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#addResultType(java.lang.String,
* boolean)
*/
public void addResultType(String aTypeName, boolean aAllAnnotatorFeatures) {
TypeOrFeature t = new TypeOrFeature_impl();
t.setType(true);
t.setName(aTypeName);
t.setAllAnnotatorFeatures(aAllAnnotatorFeatures);
mTypesAndFeatures.put(t, mDefaultLanguage);
// revert to uncompiled state
mCompiledNameToLanguageMap.clear();
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#addResultType(java.lang.String,
* boolean, java.lang.String[])
*/
public void addResultType(String aTypeName, boolean aAllAnnotatorFeatures, String[] aLanguageIDs) {
if (aLanguageIDs != null) {
// create HashSet for the aLanguageIDs with the initial capacity of the aLanguageIDs size
HashSet languagesSupported = new HashSet(aLanguageIDs.length);
// add all supported languages to at HashSet
for (int x = 0; x < aLanguageIDs.length; x++) {
// add current language to the HashSet
languagesSupported.add(aLanguageIDs[x]);
}
TypeOrFeature t = new TypeOrFeature_impl();
t.setType(true);
t.setName(aTypeName);
t.setAllAnnotatorFeatures(aAllAnnotatorFeatures);
HashSet existingLanguages = (HashSet) mTypesAndFeatures.get(t);
if (existingLanguages != null) {
existingLanguages.addAll(languagesSupported);
} else {
mTypesAndFeatures.put(t, languagesSupported);
}
// revert to uncompiled state
mCompiledNameToLanguageMap.clear();
} else {
// if aLangugeIDs is null add type with the default language
addResultType(aTypeName, aAllAnnotatorFeatures);
}
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#addResultFeature(java.lang.String)
*/
public void addResultFeature(String aFullFeatureName) {
TypeOrFeature f = new TypeOrFeature_impl();
f.setType(false);
f.setName(aFullFeatureName);
mTypesAndFeatures.put(f, mDefaultLanguage);
// revert to uncompiled state
mCompiledNameToLanguageMap.clear();
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#addResultFeature(java.lang.String,
* java.lang.String[])
*/
public void addResultFeature(String aFullFeatureName, String[] aLanguageIDs) {
if (aLanguageIDs != null) {
// create HashSet for the aLanguageIDs with the initial capacity of the aLanguageIDs size
HashSet languagesSupported = new HashSet(aLanguageIDs.length);
// add all supported languages to at HashSet
for (int x = 0; x < aLanguageIDs.length; x++) {
// add current language to the HashSet
languagesSupported.add(aLanguageIDs[x]);
}
TypeOrFeature f = new TypeOrFeature_impl();
f.setType(false);
f.setName(aFullFeatureName);
HashSet existingLanguages = (HashSet) mTypesAndFeatures.get(f);
if (existingLanguages != null) {
existingLanguages.addAll(languagesSupported);
} else {
mTypesAndFeatures.put(f, languagesSupported);
}
// revert to uncompiled state
mCompiledNameToLanguageMap.clear();
} else {
// if aLangugeIDs is null add type with the default language
addResultFeature(aFullFeatureName);
}
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#compile(org.apache.uima.cas.TypeSystem)
*/
public void compile(TypeSystem aTypeSystem) {
mCompiledNameToLanguageMap.clear();
Iterator it = mTypesAndFeatures.entrySet().iterator();
while (it.hasNext()) {
Map.Entry elem = (Map.Entry) it.next();
TypeOrFeature tof = (TypeOrFeature) elem.getKey();
if (tof.isType()) {
Type t = aTypeSystem.getType(tof.getName());
if (t != null) {
addTypeRecursive(t, aTypeSystem, (HashSet) elem.getValue(), tof.isAllAnnotatorFeatures());
}
} else // feature
{
mCompiledNameToLanguageMap.put(tof.getName(), elem.getValue());
}
}
// TODO: process the set of intersections
}
/**
* @param t
*/
private void addTypeRecursive(Type type, TypeSystem typeSystem, HashSet languages,
boolean allFeatures) {
mCompiledNameToLanguageMap.put(type.getName(), languages);
if (allFeatures) {
List features = type.getFeatures();
Iterator featIt = features.iterator();
while (featIt.hasNext()) {
Feature f = (Feature) featIt.next();
mCompiledNameToLanguageMap.put(f.getName(), languages);
}
}
// recurse on subtypes
List subtypes = typeSystem.getDirectSubtypes(type);
Iterator typeIt = subtypes.iterator();
while (typeIt.hasNext()) {
Type subtype = (Type) typeIt.next();
addTypeRecursive(subtype, typeSystem, languages, allFeatures);
}
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#containsType(java.lang.String)
*/
public boolean containsType(String aTypeName) {
if (aTypeName.indexOf(TypeSystem.FEATURE_SEPARATOR) != -1)
return false; // check against someone passing a feature name here
// if compile() has been called can be done by a hash lookup
if (!mCompiledNameToLanguageMap.isEmpty()) {
return mCompiledNameToLanguageMap.containsKey(aTypeName);
} else {
// brute force search
Iterator it = mTypesAndFeatures.keySet().iterator();
while (it.hasNext()) {
TypeOrFeature elem = (TypeOrFeature) it.next();
if (elem.isType() && aTypeName.equals(elem.getName())) {
return true;
}
}
return false;
}
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#containsType(java.lang.String,java.lang.String)
*/
public boolean containsType(String aTypeName, String language) {
if (language == null) {
return containsType(aTypeName);
}
if (aTypeName.indexOf(TypeSystem.FEATURE_SEPARATOR) != -1)
return false; // check against someone passing a feature name here
// get language without country if applicable
String baseLanguage = null;
int index = language.indexOf(LANGUAGE_SEPARATOR);
if (index > -1) {
baseLanguage = language.substring(0, index);
}
boolean found = false;
if (!mCompiledNameToLanguageMap.isEmpty()) {
// if compile() has been called can be done by a hash lookup
HashSet languages = (HashSet) mCompiledNameToLanguageMap.get(aTypeName);
if (languages != null) {
// check if tof is supported for the current language
if (UNSPECIFIED_LANGUAGE.equals(language) || languages.contains(language)
|| languages.contains(UNSPECIFIED_LANGUAGE) || languages.contains(baseLanguage)) {
// mark item found
found = true;
}
}
} else {
// brute force search
Iterator it = mTypesAndFeatures.keySet().iterator();
while (it.hasNext()) {
TypeOrFeature elem = (TypeOrFeature) it.next();
if (elem.isType() && aTypeName.equals(elem.getName())) {
HashSet languages = (HashSet) mTypesAndFeatures.get(elem);
if (languages != null) {
// check if tof is supported for the current language
if (UNSPECIFIED_LANGUAGE.equals(language) || languages.contains(language)
|| languages.contains(UNSPECIFIED_LANGUAGE) || languages.contains(baseLanguage)) {
// mark item found
return true;
}
}
}
}
}
return found;
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#containsFeature(java.lang.String)
*/
public boolean containsFeature(String aFullFeatureName) {
if (aFullFeatureName.indexOf(TypeSystem.FEATURE_SEPARATOR) == -1)
return false; // check against someone passing a type name here
// if compile() has been called can be done by a hash lookup
if (!mCompiledNameToLanguageMap.isEmpty()) {
return mCompiledNameToLanguageMap.containsKey(aFullFeatureName);
} else {
// brute force search
// (also need to consider Types with allAnnotatorFeatures = true)
String typeName = "";
int typeSeparatorIndex = aFullFeatureName.indexOf(':');
if (typeSeparatorIndex > 0) {
typeName = aFullFeatureName.substring(0, typeSeparatorIndex);
}
Iterator it = mTypesAndFeatures.keySet().iterator();
while (it.hasNext()) {
TypeOrFeature elem = (TypeOrFeature) it.next();
if ((!elem.isType() && aFullFeatureName.equals(elem.getName()))
|| (elem.isType() && elem.isAllAnnotatorFeatures() && typeName.equals(elem
.getName()))) {
return true;
}
}
return false;
}
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#containsFeature(java.lang.String,java.lang.String)
*/
public boolean containsFeature(String aFullFeatureName, String language) {
if (language == null) {
return containsFeature(aFullFeatureName);
}
if (aFullFeatureName.indexOf(TypeSystem.FEATURE_SEPARATOR) == -1)
return false; // check against someone passing a type name here
// get language without country if applicable
String baseLanguage = null;
int index = language.indexOf(LANGUAGE_SEPARATOR);
if (index > -1) {
baseLanguage = language.substring(0, index);
}
boolean found = false;
// if compile() has been called can be done by a hash lookup
if (!mCompiledNameToLanguageMap.isEmpty()) {
HashSet languages = (HashSet) mCompiledNameToLanguageMap.get(aFullFeatureName);
if (languages != null) {
// check if tof is supported for the current language
if (UNSPECIFIED_LANGUAGE.equals(language) || languages.contains(language)
|| languages.contains(UNSPECIFIED_LANGUAGE) || languages.contains(baseLanguage)) {
// mark item found
found = true;
}
}
} else {
// brute force search
// (also need to consider Types with allAnnotatorFeatures = true)
String typeName = "";
int typeSeparatorIndex = aFullFeatureName.indexOf(':');
if (typeSeparatorIndex > 0) {
typeName = aFullFeatureName.substring(0, typeSeparatorIndex);
}
Iterator it = mTypesAndFeatures.keySet().iterator();
while (it.hasNext()) {
TypeOrFeature elem = (TypeOrFeature) it.next();
if ((!elem.isType() && aFullFeatureName.equals(elem.getName()))
|| (elem.isType() && elem.isAllAnnotatorFeatures() && typeName.equals(elem
.getName()))) {
HashSet languages = (HashSet) mTypesAndFeatures.get(elem);
if (languages != null) {
// check if tof is supported for the current language
if (UNSPECIFIED_LANGUAGE.equals(language) || languages.contains(language)
|| languages.contains(UNSPECIFIED_LANGUAGE) || languages.contains(baseLanguage)) {
// mark item found
return true;
}
}
}
}
}
return found;
}
/**
* @see org.apache.uima.resource.impl.MetaDataObject_impl#getXmlizationInfo()
*/
protected XmlizationInfo getXmlizationInfo() {
return new XmlizationInfo("resultSpecification", null,
new PropertyXmlInfo[] { new PropertyXmlInfo("resultTypesAndFeatures", null) });
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#addCapabilities(org.apache.uima.resource.metadata.Capability[])
*/
public void addCapabilities(Capability[] capabilities) {
addCapabilities(capabilities, true);
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#addCapabilities(org.apache.uima.resource.metadata.Capability[],
* boolean)
*/
public void addCapabilities(Capability[] capabilities, boolean outputs) {
if (capabilities != null) {
for (int i = 0; i < capabilities.length; i++) {
TypeOrFeature[] tofs = outputs ? capabilities[i].getOutputs() : capabilities[i].getInputs();
// get supported languages
String[] supportedLanguagesArr = capabilities[i].getLanguagesSupported();
HashSet supportedLanguages = null;
if (supportedLanguagesArr != null && supportedLanguagesArr.length > 0) {
// create new HashSet with the initial capacity of the supportedLanguageArr
supportedLanguages = new HashSet(supportedLanguagesArr.length);
// add all supported languages to at HashSet
for (int x = 0; x < supportedLanguagesArr.length; x++) {
// add current language to the HashSet
supportedLanguages.add(supportedLanguagesArr[x]);
}
} else {
// if no languages are set, set default language
supportedLanguages = mDefaultLanguage;
}
for (int y = 0; y < tofs.length; y++) {
mTypesAndFeatures.put(tofs[y], supportedLanguages);
}
}
}
// revert to uncompiled state
mCompiledNameToLanguageMap.clear();
}
/**
* @see org.apache.uima.analysis_engine.ResultSpecification#removeTypeOrFeature(org.apache.uima.analysis_engine.TypeOrFeature)
*/
public void removeTypeOrFeature(TypeOrFeature aTypeOrFeature) {
// reomve Type or Feature from the
mTypesAndFeatures.remove(aTypeOrFeature);
// revert to uncompiled state
mCompiledNameToLanguageMap.clear();
}
/**
* returns a clone of the <code>ResultSpecification</code> object.
*
* @return Object copy of the current object
*/
public Object clone() {
// create new result specification
// NOTE: we don't use super.clone here, since for performance reasons
// we want to do a faster clone that what the general-purpose logic in
// MetaDataObject_impl does. This class is marked final so that
// this can't cause a problem if ResultSpecification_impl is subclassed.
ResultSpecification_impl newResultSpec = new ResultSpecification_impl();
// clone HashMaps
newResultSpec.mTypesAndFeatures = new HashMap(this.mTypesAndFeatures);
newResultSpec.mDefaultLanguage = new HashSet(this.mDefaultLanguage);
return newResultSpec;
}
}