blob: 5e6feee63cf277cab14f0414d498a8de33f21462 [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.fit.util;
import static java.util.Arrays.asList;
import static org.apache.uima.fit.util.FSCollectionFactory.createArrayFS;
import static org.apache.uima.fit.util.FSCollectionFactory.createBooleanArray;
import static org.apache.uima.fit.util.FSCollectionFactory.createByteArray;
import static org.apache.uima.fit.util.FSCollectionFactory.createDoubleArray;
import static org.apache.uima.fit.util.FSCollectionFactory.createFSList;
import static org.apache.uima.fit.util.FSCollectionFactory.createFloatArray;
import static org.apache.uima.fit.util.FSCollectionFactory.createFloatList;
import static org.apache.uima.fit.util.FSCollectionFactory.createIntArray;
import static org.apache.uima.fit.util.FSCollectionFactory.createIntegerList;
import static org.apache.uima.fit.util.FSCollectionFactory.createLongArray;
import static org.apache.uima.fit.util.FSCollectionFactory.createShortArray;
import static org.apache.uima.fit.util.FSCollectionFactory.createStringArray;
import static org.apache.uima.fit.util.FSCollectionFactory.createStringList;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.uima.cas.ArrayFS;
import org.apache.uima.cas.BooleanArrayFS;
import org.apache.uima.cas.ByteArrayFS;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.CommonArrayFS;
import org.apache.uima.cas.DoubleArrayFS;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.FeatureStructure;
import org.apache.uima.cas.FloatArrayFS;
import org.apache.uima.cas.IntArrayFS;
import org.apache.uima.cas.LongArrayFS;
import org.apache.uima.cas.ShortArrayFS;
import org.apache.uima.cas.StringArrayFS;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeSystem;
public class FSUtil {
private static Feature getMandatoryFeature(FeatureStructure aFS, String aFeature)
{
Feature feat = aFS.getType().getFeatureByBaseName(aFeature);
if (feat == null) {
throw new IllegalArgumentException("Type [" + aFS.getType() + "] has no feature with name ["
+ aFeature + "]");
}
return feat;
}
private static void requireSingleValue(Feature aFeature, Object aArray)
{
if (aArray == null) {
throw new IllegalArgumentException("Cannot set [" + aFeature.getName() + "] to a null value.");
}
if (Array.getLength(aArray) != 1) {
throw new IllegalArgumentException("Feature [" + aFeature.getName()
+ "] requires a single value but got " + asList(aArray));
}
}
private static boolean isListType(TypeSystem aTS, Type aType)
{
return aTS.subsumes(aTS.getType(CAS.TYPE_NAME_LIST_BASE), aType);
}
public static boolean hasFeature(FeatureStructure aFS, String aFeature) {
return aFS.getType().getFeatureByBaseName(aFeature) != null;
}
public static boolean isMultiValuedFeature(FeatureStructure aFS, String aFeature) {
Feature feat = aFS.getType().getFeatureByBaseName(aFeature);
return isMultiValuedFeature(aFS, feat);
}
public static boolean isMultiValuedFeature(FeatureStructure aFS, Feature feat) {
return isMultiValuedFeature(aFS.getCAS().getTypeSystem(), feat);
}
public static boolean isMultiValuedFeature(TypeSystem aTypeSystem, Feature feat) {
if (feat == null) {
return false;
}
return feat.getRange().isArray() || isListType(aTypeSystem, feat.getRange());
}
public static void setFeature(FeatureStructure aFS, String aFeature, boolean... aValue) {
Feature feat = getMandatoryFeature(aFS, aFeature);
if (feat.getRange().isPrimitive()) {
requireSingleValue(feat, aValue);
aFS.setBooleanValue(feat, aValue[0]);
}
else if (aValue == null) {
aFS.setFeatureValue(feat, null);
}
else {
aFS.setFeatureValue(feat, createBooleanArray(aFS.getCAS(), aValue));
}
}
public static void setFeature(FeatureStructure aFS, String aFeature, byte... aValue) {
Feature feat = getMandatoryFeature(aFS, aFeature);
if (feat.getRange().isPrimitive()) {
requireSingleValue(feat, aValue);
aFS.setByteValue(feat, aValue[0]);
}
else if (aValue == null) {
aFS.setFeatureValue(feat, null);
}
else {
aFS.setFeatureValue(feat, createByteArray(aFS.getCAS(), aValue));
}
}
public static void setFeature(FeatureStructure aFS, String aFeature, double... aValue) {
Feature feat = getMandatoryFeature(aFS, aFeature);
if (feat.getRange().isPrimitive()) {
requireSingleValue(feat, aValue);
aFS.setDoubleValue(feat, aValue[0]);
}
else if (aValue == null) {
aFS.setFeatureValue(feat, null);
}
else {
aFS.setFeatureValue(feat, createDoubleArray(aFS.getCAS(), aValue));
}
}
public static void setFeature(FeatureStructure aFS, String aFeature, float... aValue) {
Feature feat = getMandatoryFeature(aFS, aFeature);
if (feat.getRange().isPrimitive()) {
requireSingleValue(feat, aValue);
aFS.setFloatValue(feat, aValue[0]);
}
else if (aValue == null) {
aFS.setFeatureValue(feat, null);
}
else if (feat.getRange().isArray()) {
aFS.setFeatureValue(feat, createFloatArray(aFS.getCAS(), aValue));
}
else {
aFS.setFeatureValue(feat, createFloatList(aFS.getCAS(), aValue));
}
}
public static void setFeature(FeatureStructure aFS, String aFeature, int... aValue) {
Feature feat = getMandatoryFeature(aFS, aFeature);
if (feat.getRange().isPrimitive()) {
requireSingleValue(feat, aValue);
aFS.setIntValue(feat, aValue[0]);
}
else if (aValue == null) {
aFS.setFeatureValue(feat, null);
}
else if (feat.getRange().isArray()) {
aFS.setFeatureValue(feat, createIntArray(aFS.getCAS(), aValue));
}
else {
aFS.setFeatureValue(feat, createIntegerList(aFS.getCAS(), aValue));
}
}
public static void setFeature(FeatureStructure aFS, String aFeature, long... aValue) {
Feature feat = getMandatoryFeature(aFS, aFeature);
if (feat.getRange().isPrimitive()) {
requireSingleValue(feat, aValue);
aFS.setLongValue(feat, aValue[0]);
}
else if (aValue == null) {
aFS.setFeatureValue(feat, null);
}
else {
aFS.setFeatureValue(feat, createLongArray(aFS.getCAS(), aValue));
}
}
public static void setFeature(FeatureStructure aFS, String aFeature, short... aValue) {
Feature feat = getMandatoryFeature(aFS, aFeature);
if (feat.getRange().isPrimitive()) {
requireSingleValue(feat, aValue);
aFS.setShortValue(feat, aValue[0]);
}
else if (aValue == null) {
aFS.setFeatureValue(feat, null);
}
else {
aFS.setFeatureValue(feat, createShortArray(aFS.getCAS(), aValue));
}
}
public static void setFeature(FeatureStructure aFS, String aFeature, String... aValue) {
Feature feat = getMandatoryFeature(aFS, aFeature);
if (feat.getRange().isPrimitive()) {
requireSingleValue(feat, aValue);
aFS.setStringValue(feat, aValue[0]);
}
else if (aValue == null) {
aFS.setFeatureValue(feat, null);
}
else if (feat.getRange().isArray()) {
aFS.setFeatureValue(feat, createStringArray(aFS.getCAS(), aValue));
}
else {
aFS.setFeatureValue(feat, createStringList(aFS.getCAS(), aValue));
}
}
public static void setFeature(FeatureStructure aFS, String aFeature, FeatureStructure... aValue) {
Feature feat = getMandatoryFeature(aFS, aFeature);
if (feat.getRange().isArray()) {
aFS.setFeatureValue(feat, createArrayFS(aFS.getCAS(), aValue));
}
else if (aValue == null) {
aFS.setFeatureValue(feat, null);
}
else if (isListType(aFS.getCAS().getTypeSystem(), feat.getRange())) {
aFS.setFeatureValue(feat, createFSList(aFS.getCAS(), aValue));
}
else {
requireSingleValue(feat, aValue);
aFS.setFeatureValue(feat, aValue[0]);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void setFeature(FeatureStructure aFS, String aFeature, Collection aValue) {
Feature feat = getMandatoryFeature(aFS, aFeature);
if (aValue == null) {
aFS.setFeatureValue(feat, null);
}
else if (feat.getRange().isArray()) {
switch (feat.getRange().getName()) {
case CAS.TYPE_NAME_BOOLEAN_ARRAY:
aFS.setFeatureValue(feat, createBooleanArray(aFS.getCAS(), aValue));
break;
case CAS.TYPE_NAME_BYTE_ARRAY:
aFS.setFeatureValue(feat, createByteArray(aFS.getCAS(), aValue));
break;
case CAS.TYPE_NAME_DOUBLE_ARRAY:
aFS.setFeatureValue(feat, createDoubleArray(aFS.getCAS(), aValue));
break;
case CAS.TYPE_NAME_FLOAT_ARRAY:
aFS.setFeatureValue(feat, createFloatArray(aFS.getCAS(), aValue));
break;
case CAS.TYPE_NAME_INTEGER_ARRAY:
aFS.setFeatureValue(feat, createIntArray(aFS.getCAS(), aValue));
break;
case CAS.TYPE_NAME_LONG_ARRAY:
aFS.setFeatureValue(feat, createLongArray(aFS.getCAS(), aValue));
break;
case CAS.TYPE_NAME_SHORT_ARRAY:
aFS.setFeatureValue(feat, createShortArray(aFS.getCAS(), aValue));
break;
case CAS.TYPE_NAME_STRING_ARRAY:
aFS.setFeatureValue(feat, createStringArray(aFS.getCAS(), aValue));
break;
default:
aFS.setFeatureValue(feat, createArrayFS(aFS.getCAS(), aValue));
break;
}
}
else {
switch (feat.getRange().getName()) {
case CAS.TYPE_NAME_FLOAT_LIST:
aFS.setFeatureValue(feat, createFloatList(aFS.getCAS(), aValue));
break;
case CAS.TYPE_NAME_INTEGER_LIST:
aFS.setFeatureValue(feat, createIntegerList(aFS.getCAS(), aValue));
break;
case CAS.TYPE_NAME_STRING_LIST:
aFS.setFeatureValue(feat, createStringList(aFS.getCAS(), aValue));
break;
default:
aFS.setFeatureValue(feat, createFSList(aFS.getCAS(), aValue));
break;
}
}
}
public static <T> T getFeature(FeatureStructure aFS, String aFeature, Class<T> aClazz)
{
Feature feat = getMandatoryFeature(aFS, aFeature);
return getFeature(aFS, feat, aClazz);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T> T getFeature(FeatureStructure aFS, Feature aFeature, Class<T> aClazz)
{
if (aFeature.getRange().isPrimitive()) {
switch (aFeature.getRange().getName()) {
case CAS.TYPE_NAME_BOOLEAN:
return aClazz.cast(aFS.getBooleanValue(aFeature));
case CAS.TYPE_NAME_BYTE:
return aClazz.cast(aFS.getByteValue(aFeature));
case CAS.TYPE_NAME_DOUBLE:
return aClazz.cast(aFS.getDoubleValue(aFeature));
case CAS.TYPE_NAME_FLOAT:
return aClazz.cast(aFS.getFloatValue(aFeature));
case CAS.TYPE_NAME_INTEGER:
return aClazz.cast(aFS.getIntValue(aFeature));
case CAS.TYPE_NAME_LONG:
return aClazz.cast(aFS.getLongValue(aFeature));
case CAS.TYPE_NAME_SHORT:
return aClazz.cast(aFS.getShortValue(aFeature));
case CAS.TYPE_NAME_STRING:
return aClazz.cast(aFS.getStringValue(aFeature));
default:
throw new IllegalArgumentException("Unable to coerce value of feature [" + aFeature.getName()
+ "] with type [" + aFeature.getRange().getName() + "] into [" + aClazz.getName() + "]");
}
}
FeatureStructure value = aFS.getFeatureValue(aFeature);
// "null" case
if (value == null) {
return null;
}
// Here we store the values before we coerce them into the final target type
// "target" is actually an array
Object target;
int length;
// Handle case where feature is an array
if (value instanceof CommonArrayFS) {
// Shortcut if the user explicitly requests an array type
if (!Object.class.equals(aClazz) && aClazz.isAssignableFrom(value.getClass())) {
return (T) value;
}
CommonArrayFS source = (CommonArrayFS) value;
length = source.size();
if (value instanceof BooleanArrayFS) {
target = new boolean[length];
((BooleanArrayFS) source).copyToArray(0, (boolean[]) target, 0, length);
}
else if (value instanceof ByteArrayFS) {
target = new byte[length];
((ByteArrayFS) source).copyToArray(0, (byte[]) target, 0, length);
}
else if (value instanceof DoubleArrayFS) {
target = new double[length];
((DoubleArrayFS) source).copyToArray(0, (double[]) target, 0, length);
}
else if (value instanceof FloatArrayFS) {
target = new float[length];
((FloatArrayFS) source).copyToArray(0, (float[]) target, 0, length);
}
else if (value instanceof IntArrayFS) {
target = new int[length];
((IntArrayFS) source).copyToArray(0, (int[]) target, 0, length);
}
else if (value instanceof LongArrayFS) {
target = new long[length];
((LongArrayFS) source).copyToArray(0, (long[]) target, 0, length);
}
else if (value instanceof ShortArrayFS) {
target = new short[length];
((ShortArrayFS) source).copyToArray(0, (short[]) target, 0, length);
}
else if (value instanceof StringArrayFS) {
target = new String[length];
((StringArrayFS) source).copyToArray(0, (String[]) target, 0, length);
}
else {
if (aClazz.isArray()) {
target = Array.newInstance(aClazz.getComponentType(), length);
}
else {
target = new FeatureStructure[length];
}
((ArrayFS) source).copyToArray(0, (FeatureStructure[]) target, 0, length);
}
}
// Handle case where feature is a list
else if (isListType(aFS.getCAS().getTypeSystem(), aFeature.getRange())) {
// Shortcut if the user explicitly requests a list type
if (!Object.class.equals(aClazz) && aClazz.isAssignableFrom(value.getClass())) {
return (T) value;
}
// Get length of list
length = 0;
{
FeatureStructure cur = value;
// We assume to by facing a non-empty element if it has a "head" feature
while (cur.getType().getFeatureByBaseName(CAS.FEATURE_BASE_NAME_HEAD) != null) {
length++;
cur = cur.getFeatureValue(cur.getType().getFeatureByBaseName(CAS.FEATURE_BASE_NAME_TAIL));
}
}
switch (aFeature.getRange().getName()) {
case CAS.TYPE_NAME_FLOAT_LIST: {
float[] floatTarget = new float[length];
int i = 0;
FeatureStructure cur = value;
// We assume to by facing a non-empty element if it has a "head" feature
while (cur.getType().getFeatureByBaseName(CAS.FEATURE_BASE_NAME_HEAD) != null) {
floatTarget[i] = cur.getFloatValue(cur.getType().getFeatureByBaseName(
CAS.FEATURE_BASE_NAME_HEAD));
cur = cur.getFeatureValue(cur.getType()
.getFeatureByBaseName(CAS.FEATURE_BASE_NAME_TAIL));
}
target = floatTarget;
break;
}
case CAS.TYPE_NAME_INTEGER_LIST: {
int[] intTarget = new int[length];
int i = 0;
FeatureStructure cur = value;
// We assume to by facing a non-empty element if it has a "head" feature
while (cur.getType().getFeatureByBaseName(CAS.FEATURE_BASE_NAME_HEAD) != null) {
intTarget[i] = cur.getIntValue(cur.getType().getFeatureByBaseName(
CAS.FEATURE_BASE_NAME_HEAD));
cur = cur.getFeatureValue(cur.getType()
.getFeatureByBaseName(CAS.FEATURE_BASE_NAME_TAIL));
}
target = intTarget;
break;
}
case CAS.TYPE_NAME_STRING_LIST: {
String[] stringTarget = new String[length];
int i = 0;
FeatureStructure cur = value;
// We assume to by facing a non-empty element if it has a "head" feature
while (cur.getType().getFeatureByBaseName(CAS.FEATURE_BASE_NAME_HEAD) != null) {
stringTarget[i] = cur.getStringValue(cur.getType().getFeatureByBaseName(
CAS.FEATURE_BASE_NAME_HEAD));
cur = cur.getFeatureValue(cur.getType()
.getFeatureByBaseName(CAS.FEATURE_BASE_NAME_TAIL));
}
target = stringTarget;
break;
}
default: {
if (aClazz.isArray()) {
target = Array.newInstance(aClazz.getComponentType(), length);
} else {
target = new FeatureStructure[length];
}
int i = 0;
FeatureStructure cur = value;
// We assume to by facing a non-empty element if it has a "head" feature
while (cur.getType().getFeatureByBaseName(CAS.FEATURE_BASE_NAME_HEAD) != null) {
Array.set(target, i,
cur.getFeatureValue(cur.getType().getFeatureByBaseName(
CAS.FEATURE_BASE_NAME_HEAD)));
i++;
cur = cur.getFeatureValue(cur.getType()
.getFeatureByBaseName(CAS.FEATURE_BASE_NAME_TAIL));
}
break;
}
}
}
else if (aClazz.isAssignableFrom(value.getClass())) {
return (T) value;
}
else if (aFS.getCAS().getTypeSystem()
.subsumes(CasUtil.getType(aFS.getCAS(), aClazz), aFeature.getRange())) {
return (T) value;
}
else {
throw new IllegalArgumentException("Unable to coerce value of feature [" + aFeature.getName()
+ "] with type [" + aFeature.getRange().getName() + "] into [" + aClazz.getName() + "]");
}
// Handle case where return value is an array
if (aClazz.isArray()) {
return aClazz.cast(target);
}
// Handle case where return value is Object
Class targetClass = aClazz;
if (Object.class.equals(aClazz)) {
targetClass = List.class;
}
// Handle case where return value is a collection
if (Collection.class.isAssignableFrom(targetClass)) {
Collection targetCollection;
if (targetClass.isInterface()) {
// If the target is an interface, try using a default implementation;
if (List.class.isAssignableFrom(targetClass)) {
targetCollection = new ArrayList(length);
}
else if (Set.class.isAssignableFrom(targetClass)) {
targetCollection = new HashSet(length);
}
else {
throw new IllegalArgumentException("Unable to coerce value of feature [" + aFeature.getName()
+ "] with type [" + aFeature.getRange().getName() + "] into [" + targetClass.getName() + "]");
}
}
else {
// Try to instantiate using 0-args constructor
try {
targetCollection = (Collection) targetClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new IllegalArgumentException("Unable to coerce value of feature [" + aFeature.getName()
+ "] with type [" + aFeature.getRange().getName() + "] into [" + targetClass.getName() + "]", e);
}
}
for (int i = 0; i < length; i++) {
targetCollection.add(Array.get(target, i));
}
return (T) targetClass.cast(targetCollection);
}
throw new IllegalArgumentException("Unable to coerce value of feature [" + aFeature.getName()
+ "] with type [" + aFeature.getRange().getName() + "] into [" + targetClass.getName() + "]");
}
}