blob: 95c595ef83d593c89367fb63a67aa9a8eabdaf34 [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.cas.impl;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_Boolean;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_BooleanRef;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_Byte;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_ByteRef;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_DoubleRef;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_Float;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_HeapRef;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_Int;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_LongRef;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_Short;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_ShortRef;
import static org.apache.uima.cas.impl.SlotKinds.SlotKind.Slot_StrRef;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.WeakHashMap;
import java.util.stream.Collectors;
import org.apache.uima.UIMAFramework;
import org.apache.uima.UIMARuntimeException;
import org.apache.uima.cas.CAS;
import org.apache.uima.cas.CASRuntimeException;
import org.apache.uima.cas.Feature;
import org.apache.uima.cas.Type;
import org.apache.uima.cas.TypeNameSpace;
import org.apache.uima.cas.TypeSystem;
import org.apache.uima.cas.admin.CASAdminException;
import org.apache.uima.cas.admin.TypeSystemMgr;
import org.apache.uima.cas.impl.FSClassRegistry.JCasClassInfo;
import org.apache.uima.cas.impl.SlotKinds.SlotKind;
import org.apache.uima.internal.util.Misc;
import org.apache.uima.jcas.JCasRegistry;
import org.apache.uima.jcas.cas.AnnotationBase;
import org.apache.uima.jcas.cas.BooleanArray;
import org.apache.uima.jcas.cas.ByteArray;
import org.apache.uima.jcas.cas.CommonList;
import org.apache.uima.jcas.cas.DoubleArray;
import org.apache.uima.jcas.cas.EmptyFSList;
import org.apache.uima.jcas.cas.EmptyFloatList;
import org.apache.uima.jcas.cas.EmptyIntegerList;
import org.apache.uima.jcas.cas.EmptyStringList;
import org.apache.uima.jcas.cas.FSArray;
import org.apache.uima.jcas.cas.FSList;
import org.apache.uima.jcas.cas.FloatArray;
import org.apache.uima.jcas.cas.FloatList;
import org.apache.uima.jcas.cas.IntegerArray;
import org.apache.uima.jcas.cas.IntegerList;
import org.apache.uima.jcas.cas.LongArray;
import org.apache.uima.jcas.cas.NonEmptyFSList;
import org.apache.uima.jcas.cas.NonEmptyFloatList;
import org.apache.uima.jcas.cas.NonEmptyIntegerList;
import org.apache.uima.jcas.cas.NonEmptyStringList;
import org.apache.uima.jcas.cas.ShortArray;
import org.apache.uima.jcas.cas.Sofa;
import org.apache.uima.jcas.cas.StringArray;
import org.apache.uima.jcas.cas.StringList;
import org.apache.uima.jcas.cas.TOP;
import org.apache.uima.jcas.tcas.Annotation;
import org.apache.uima.util.Logger;
import org.apache.uima.util.impl.Constants;
/**
* Type system implementation.
*
* This class has static final (constant) values for built-in type codes, feature codes, feature offsets, and feature isInt.
* - these are used
* -- for various type-specific internal use
* -- static final constants in the built-in JCas class definitions
* - these are set by hand as final constants
*
* Threading: An instance of this object needs to be thread safe after creation, because multiple threads
* are reading info from it.
* - During creation, only one thread is creating.
*
* Association with Class Loaders, after type system is committed
* Because JCas classes are generated from the merged type system, and then loaded under some class loader,
* several use cases need to be accommodated.
*
* Multiple type systems committed in sequence within one UIMA application.
* - Under one class loader
* -- therefore, they share one JCas loaded classes definition
* - OK provided type system is compatible with JCas loaded definitions
*
* At commit time, a type system is compared with existing ones; if it is equal, then
* the typeImpl and featureImpls and all other instance vars are replaced with existing ones.
* -- this removes issues in type system mapping needed between "equal" type systems to get feature validation to work.
* -- implemented via custom hashcode and equals.
*
*/
public class TypeSystemImpl implements TypeSystem, TypeSystemMgr, LowLevelTypeSystem {
private static final boolean IS_TRACE_JCAS_EXPAND = false; // set to show jcas expands of types
/**
* Define this JVM property to disable equal type system consolidation.
* When a type system is committed, it normally is compared with other committed type systems
* that are still available (i.e. not garbage collected) to see if an existing type system
* is equal to the new one.
*
* - if so, then the existing one is reused.
*
* This may cause problems for applications which have obtained references to types and
* features of a type system before it is committed; the committed version may have
* different (but "equal") types and features.
*
*/
public static final String DISABLE_TYPESYSTEM_CONSOLIDATION = "uima.disable_typesystem_consolidation";
/**
* public for test case
*/
public static final boolean IS_DISABLE_TYPESYSTEM_CONSOLIDATION = // true || // debug
Misc.getNoValueSystemProperty(DISABLE_TYPESYSTEM_CONSOLIDATION);
// private final static String DECOMPILE_JCAS = "uima.decompile.jcas";
// private final static boolean IS_DECOMPILE_JCAS = Misc.getNoValueSystemProperty(DECOMPILE_JCAS);
// private final static Set<String> decompiled = (IS_DECOMPILE_JCAS) ? new HashSet<String>(256) : null;
static private final MethodHandle MHC_MINUS_1 = MethodHandles.constant(int.class, -1);
/**
* Type code that is returned on unknown type names.
*/
static final int UNKNOWN_TYPE_CODE = 0;
private static final int LEAST_TYPE_CODE = 1;
// private static final int INVALID_TYPE_CODE = 0;
private static final int LEAST_FEATURE_CODE = 1;
static final String ARRAY_TYPE_SUFFIX = "[]";
/**
* HEAP_STORED_ARRAY flag is kept for ser/deserialization compatibility
*/
private static final boolean HEAP_STORED_ARRAY = true;
/**
* For a given class loader, prevent redefinitions of the same type system from
*
*/
// private static final Map<ClassLoader, Set<TypeSystemImpl>> committedTypeSystemsByClassLoader =
// Collections.newSetFromMap(
// new WeakHashMap<TypeSystemImpl, Boolean>()));
private final static int INIT_SIZE_ARRAYS_BUILT_IN_TYPES = 64; // approximate... used for array sizing only
// static maps ok for now - only built-in mappings stored here
// which are the same for all type system instances
/**
* Map from component name to built-in array name
*/
private final static Map<String, String> builtInArrayComponentName2ArrayTypeName = new HashMap<String, String>(9);
static {
builtInArrayComponentName2ArrayTypeName.put(CAS.TYPE_NAME_TOP, CAS.TYPE_NAME_FS_ARRAY);
builtInArrayComponentName2ArrayTypeName.put(CAS.TYPE_NAME_BOOLEAN, CAS.TYPE_NAME_BOOLEAN_ARRAY);
builtInArrayComponentName2ArrayTypeName.put(CAS.TYPE_NAME_BYTE, CAS.TYPE_NAME_BYTE_ARRAY);
builtInArrayComponentName2ArrayTypeName.put(CAS.TYPE_NAME_SHORT, CAS.TYPE_NAME_SHORT_ARRAY);
builtInArrayComponentName2ArrayTypeName.put(CAS.TYPE_NAME_INTEGER, CAS.TYPE_NAME_INTEGER_ARRAY);
builtInArrayComponentName2ArrayTypeName.put(CAS.TYPE_NAME_FLOAT, CAS.TYPE_NAME_FLOAT_ARRAY);
builtInArrayComponentName2ArrayTypeName.put(CAS.TYPE_NAME_LONG, CAS.TYPE_NAME_LONG_ARRAY);
builtInArrayComponentName2ArrayTypeName.put(CAS.TYPE_NAME_DOUBLE, CAS.TYPE_NAME_DOUBLE_ARRAY);
builtInArrayComponentName2ArrayTypeName.put(CAS.TYPE_NAME_STRING, CAS.TYPE_NAME_STRING_ARRAY);
// builtInArrayComponentName2ArrayTypeName.put(CAS.TYPE_NAME_JAVA_OBJECT, CAS.TYPE_NAME_JAVA_OBJECT_ARRAY);
}
private final static Map<String, SlotKind> slotKindsForNonArrays = new HashMap<>(9);
static {
slotKindsForNonArrays.put(CAS.TYPE_NAME_STRING, Slot_StrRef);
slotKindsForNonArrays.put(CAS.TYPE_NAME_INTEGER, Slot_Int);
slotKindsForNonArrays.put(CAS.TYPE_NAME_BOOLEAN, Slot_Boolean);
slotKindsForNonArrays.put(CAS.TYPE_NAME_BYTE, Slot_Byte);
slotKindsForNonArrays.put(CAS.TYPE_NAME_SHORT, Slot_Short);
slotKindsForNonArrays.put(CAS.TYPE_NAME_FLOAT, Slot_Float);
slotKindsForNonArrays.put(CAS.TYPE_NAME_LONG, Slot_LongRef);
slotKindsForNonArrays.put(CAS.TYPE_NAME_DOUBLE, Slot_DoubleRef);
}
// private static final Object GLOBAL_TYPESYS_LOCK = new Object();
// private static final Set<String> builtInsWithAltNames = new HashSet<String>();
// static {Misc.addAll(builtInsWithAltNames,
// CAS.TYPE_NAME_TOP,
// CAS.TYPE_NAME_STRING_ARRAY,
// CAS.TYPE_NAME_BOOLEAN_ARRAY,
// CAS.TYPE_NAME_BYTE_ARRAY,
// CAS.TYPE_NAME_SHORT_ARRAY,
// CAS.TYPE_NAME_INTEGER_ARRAY,
// CAS.TYPE_NAME_LONG_ARRAY,
// CAS.TYPE_NAME_FS_ARRAY,
// CAS.TYPE_NAME_FLOAT_ARRAY,
// CAS.TYPE_NAME_DOUBLE_ARRAY,
// CAS.TYPE_NAME_EMPTY_FLOAT_LIST,
// CAS.TYPE_NAME_EMPTY_FS_LIST,
// CAS.TYPE_NAME_EMPTY_INTEGER_LIST,
// CAS.TYPE_NAME_EMPTY_STRING_LIST,
// CAS.TYPE_NAME_FLOAT_LIST,
// CAS.TYPE_NAME_FS_LIST,
// CAS.TYPE_NAME_INTEGER_LIST,
// CAS.TYPE_NAME_STRING_LIST,
// CAS.TYPE_NAME_NON_EMPTY_FLOAT_LIST,
// CAS.TYPE_NAME_NON_EMPTY_FS_LIST,
// CAS.TYPE_NAME_NON_EMPTY_INTEGER_LIST,
// CAS.TYPE_NAME_NON_EMPTY_STRING_LIST,
// CAS.TYPE_NAME_SOFA,
// CAS.TYPE_NAME_ANNOTATION_BASE,
// CAS.TYPE_NAME_ANNOTATION,
// CAS.TYPE_NAME_DOCUMENT_ANNOTATION
//// CAS.TYPE_NAME_JAVA_OBJECT_ARRAY
// );
// }
final private static Map<TypeSystemImpl, WeakReference<TypeSystemImpl>> committedTypeSystems = Collections.synchronizedMap(new WeakHashMap<>());
// /** OBSOLETE with BETA and later levels
// * used to pass the type being loaded reference to the JCas static initializer code,
// * referenced from the TypeSystemImpl.getAdjustedFeatureOffset([featurename]) method.
// */
// public final static ThreadLocal<TypeImpl> typeBeingLoadedThreadLocal = new ThreadLocal<TypeImpl>();
/******************************************
* I N S T A N C E V A R I A B L E S *
******************************************/
// private final TypeImpl[] allTypesForByteCodeGen;
//
// private FeatureStructureClassGen featureStructureClassGen = new FeatureStructureClassGen();
// private FSClassRegistry fsClassRegistry; // a new instance is created at commit time.
// the loaded JCas cover classes, generators. index is typecode; value is JCas cover class which may belong to a supertype.
// OK because the instance of this class FSClassRegistry is one per Type System
// not final because set after all types are defined and committed
// no longer used July 2016 - info moved into individual typeImpls
// JCasClassInfo[] jcasClassesInfo;
/**
* Map from built-in array name to component Type
*/
private final Map<String, TypeImpl> arrayName2ComponentType = new HashMap<String, TypeImpl>(9);
// not static in general because need different instances for each type system
// because instances have direct subtypes
final TypeImpl topType;
public final TypeImpl intType;
public final TypeImpl stringType;
public final TypeImpl floatType;
final TypeImpl arrayBaseType;
final TypeImpl_array intArrayType;
final TypeImpl_array floatArrayType;
final TypeImpl_array stringArrayType;
final TypeImpl_array fsArrayType;
final TypeImpl_array topArrayType; // same as fsArrayType
public final TypeImpl sofaType; // public needed for CasCopier
public final TypeImpl annotType;
public final TypeImpl annotBaseType;
public final TypeImpl docType;
public final TypeImpl byteType;
final TypeImpl_array byteArrayType;
public final TypeImpl booleanType;
final TypeImpl_array booleanArrayType;
public final TypeImpl shortType;
final TypeImpl_array shortArrayType;
public final TypeImpl longType;
final TypeImpl_array longArrayType;
public final TypeImpl doubleType;
final TypeImpl_array doubleArrayType;
// final TypeImpl_javaObject javaObjectType; // for Map, List, etc.
// final TypeImpl_array javaObjectArrayType; // for arrays of these
final TypeImpl listBaseType;
public final TypeImpl_list intListType;
public final TypeImpl_list floatListType;
public final TypeImpl_list stringListType;
public final TypeImpl_list fsListType;
public final TypeImpl_list intEListType;
public final TypeImpl_list floatEListType;
public final TypeImpl_list stringEListType;
public final TypeImpl_list fsEListType;
public final TypeImpl_list intNeListType;
public final TypeImpl_list floatNeListType;
public final TypeImpl_list stringNeListType;
public final TypeImpl_list fsNeListType;
// no longer built-in for better backwards compatibility
// public final TypeImpl fsArrayListType;
// public final TypeImpl intArrayListType;
// public final TypeImpl fsHashSetType;
// /**
// * List indexed by typecode
// * Value is an List<TypeImpl> of the directly subsumed types (just one level below)
// */
// private final List<List<TypeImpl>> directSubtypes = new ArrayList<>(); // ordered collection of Lists of direct subtypes
// {directSubtypes.add(null);} // 0th element skipped
// List<List<TypeImpl>> getDirectSubtypes() { return directSubtypes; }
//
// /**
// * @param typecode of type having subtypes
// * @return List of direct subtypes
// */
// List<TypeImpl> getDirectSubtypes(int typecode) {
// if (typecode >= directSubtypes.size()) {
// List<TypeImpl> r = new ArrayList<>();
// directSubtypes.add(typecode, r);
// return r;
// }
// return directSubtypes.get(typecode);
// }
/**
* Map from fully qualified type name to TypeImpl
*/
final Map<String, TypeImpl> typeName2TypeImpl = new HashMap<>(64);
/**
* Map from array component Type to the corresponding array type
*/
private Map<Type, Type> arrayComponentTypeToArrayType = new IdentityHashMap<>();
/**
* An ArrayList, unsynchronized, indexed by typeCode, of Type objects
*/
final List<TypeImpl> types = new ArrayList<>(INIT_SIZE_ARRAYS_BUILT_IN_TYPES);
{ types.add(null); } // use up slot 0
/**
* Used to go from a JCas class's JCasTypeID to the corresponding UIMA type for this type system.
* - when doing "new Foo(jcas)"
* - when referring to a type using its JCas typeID
*
* Used as a map, the key is the JCas loaded type id, set once when each JCas class is loaded.
* value is the corresponding TypeImpl
*
* When multiple type systems are being initialized in parallel, this list maybe updated
* on different threads. Access to it is synchronized on the object itself
*
* A single JCas type ID (corresponding to a single JCas type) might be used for many UIMA types.
* but they are always in a type hierarchy, and the top most one is the one stored here
*/
private final List<TypeImpl> jcasRegisteredTypes = new ArrayList<>(INIT_SIZE_ARRAYS_BUILT_IN_TYPES);
/**
* An ArrayList, unsynchronized, indexed by feature code, of FeatureImpl objects
*/
final List<FeatureImpl> features = new ArrayList<>(INIT_SIZE_ARRAYS_BUILT_IN_TYPES);
{ features.add(null); } // use up slot 0
// // An ArrayList (unsynchronized) of FeatureImpl objects.
// private final List<Feature> features;
// /**
// * array of parent typeCodes indexed by typeCode
// */
// private final IntVector parents;
// // String sets for string subtypes.
// private final List<String[]> stringSets;
// // This map contains an entry for every subtype of the string type. The value is a pointer into
// // the stringSets array list.
// private final IntRedBlackTree stringSetMap = new IntRedBlackTree();
// Is the type system locked?
private boolean locked = false;
// private int numTypeNames = 0;
//
// private int numFeatureNames = 0;
// map from type code to TypeInfo instance for that type code,
// set up lazily
// TypeInfo[] typeInfoArray;
// saw evidence that in some cases the setup is called on the same instance on two threads
// must be volatile to force the right memory barriers
volatile boolean areBuiltInTypesSetup = false;
// private final DecompilerSettings decompilerSettings = (IS_DECOMPILE_JCAS) ? DecompilerSettings.javaDefaults() : null;
FeatureImpl startFeat;
FeatureImpl endFeat;
FeatureImpl langFeat;
FeatureImpl sofaNum;
FeatureImpl sofaId;
FeatureImpl sofaMime;
FeatureImpl sofaArray;
FeatureImpl sofaString;
FeatureImpl sofaUri;
FeatureImpl annotBaseSofaFeat;
/**
* Cache for implementing map from type code -> FsGenerator
* Shared by all CASes using this type system
*
* maps from classloader to generator set for non-pears
*
*/
private final Map<ClassLoader, FsGenerator3[]> generatorsByClassLoader = new IdentityHashMap<>();
/**
* Cache for implementing map from type code -> FsGenerator
* Shared by all CASes using this type system
*
* maps from classloader to generator set for pears
*
*/
private final Map<ClassLoader, FsGenerator3[]> generators4pearsByClassLoader = new IdentityHashMap<>();
private int nextI; // temp value used in computing adjusted offsets
private int nextR; // temp value used in computing adjusted offsets
private Map<String, JCasClassInfo> type2jcci; // temp value used in computing adjusted offsets
private Lookup lookup;
private ClassLoader cl_for_commit;
private boolean skip_loading_user_jcas = false;
public TypeSystemImpl() {
// set up meta info (TypeImpl) for built-in types
/****************************************************************
* D O N O T C H A N G E T H I S O R D E R I N G ! ! *
* --- ----- ----------- ------- -------------------
****************************************************************/
// Create top type.
topType = new TypeImpl(CAS.TYPE_NAME_TOP, this, null, TOP.class);
// Add basic data types.
intType = new TypeImpl_primitive(CAS.TYPE_NAME_INTEGER, this, topType, int.class);
floatType = new TypeImpl_primitive(CAS.TYPE_NAME_FLOAT, this, topType, float.class);
stringType = new TypeImpl_string(CAS.TYPE_NAME_STRING, this, topType, String.class);
// Add arrays.
arrayBaseType = new TypeImpl(CAS.TYPE_NAME_ARRAY_BASE, this, topType);
topArrayType = fsArrayType = addArrayType(topType, Slot_HeapRef, HEAP_STORED_ARRAY, FSArray.class);
floatArrayType = addArrayType(floatType, Slot_Float, HEAP_STORED_ARRAY, FloatArray.class);
intArrayType = addArrayType(intType, Slot_Int, HEAP_STORED_ARRAY, IntegerArray.class);
stringArrayType = addArrayType(stringType, Slot_StrRef, HEAP_STORED_ARRAY, StringArray.class);
/**********************************************************************************************
* Add Lists *
* The Tail feature is not factored out into listBaseType because it returns a typed value. *
**********************************************************************************************/
listBaseType = new TypeImpl(CAS.TYPE_NAME_LIST_BASE, this, topType);
// FS list
fsListType = new TypeImpl_list(CAS.TYPE_NAME_FS_LIST, topType, this, listBaseType, FSList.class);
fsEListType = new TypeImpl_list(CAS.TYPE_NAME_EMPTY_FS_LIST, topType, this, fsListType, EmptyFSList.class);
fsNeListType = new TypeImpl_list(CAS.TYPE_NAME_NON_EMPTY_FS_LIST, topType, this, fsListType, NonEmptyFSList.class);
addFeature(CAS.FEATURE_BASE_NAME_TAIL, fsNeListType, fsListType, true);
addFeature(CAS.FEATURE_BASE_NAME_HEAD, fsNeListType, topType, true);
// Float list
floatListType = new TypeImpl_list(CAS.TYPE_NAME_FLOAT_LIST, floatType, this, listBaseType, FloatList.class);
floatEListType = new TypeImpl_list(CAS.TYPE_NAME_EMPTY_FLOAT_LIST, floatType, this, floatListType, EmptyFloatList.class);
floatNeListType = new TypeImpl_list(CAS.TYPE_NAME_NON_EMPTY_FLOAT_LIST, floatType, this, floatListType, NonEmptyFloatList.class);
addFeature(CAS.FEATURE_BASE_NAME_TAIL, floatNeListType, floatListType, true);
addFeature(CAS.FEATURE_BASE_NAME_HEAD, floatNeListType, floatType, false);
// Integer list
intListType = new TypeImpl_list(CAS.TYPE_NAME_INTEGER_LIST, intType, this, listBaseType, IntegerList.class);
intEListType = new TypeImpl_list(CAS.TYPE_NAME_EMPTY_INTEGER_LIST, intType, this, intListType, EmptyIntegerList.class);
intNeListType = new TypeImpl_list(CAS.TYPE_NAME_NON_EMPTY_INTEGER_LIST, intType, this, intListType, NonEmptyIntegerList.class);
addFeature(CAS.FEATURE_BASE_NAME_TAIL, intNeListType, intListType, true);
addFeature(CAS.FEATURE_BASE_NAME_HEAD, intNeListType, intType, false);
// String list
stringListType = new TypeImpl_list(CAS.TYPE_NAME_STRING_LIST, stringType, this, listBaseType, StringList.class);
stringEListType = new TypeImpl_list(CAS.TYPE_NAME_EMPTY_STRING_LIST, stringType, this, stringListType, EmptyStringList.class);
stringNeListType = new TypeImpl_list(CAS.TYPE_NAME_NON_EMPTY_STRING_LIST, stringType, this, stringListType, NonEmptyStringList.class);
addFeature(CAS.FEATURE_BASE_NAME_TAIL, stringNeListType, stringListType, true);
addFeature(CAS.FEATURE_BASE_NAME_HEAD, stringNeListType, stringType, false);
booleanType = new TypeImpl_primitive(CAS.TYPE_NAME_BOOLEAN, this, topType, boolean.class);
byteType = new TypeImpl_primitive(CAS.TYPE_NAME_BYTE, this, topType, byte.class);
shortType = new TypeImpl_primitive(CAS.TYPE_NAME_SHORT, this, topType, short.class);
longType = new TypeImpl_primitive(CAS.TYPE_NAME_LONG, this, topType, long.class);
doubleType = new TypeImpl_primitive(CAS.TYPE_NAME_DOUBLE, this, topType, double.class);
// array type initialization must follow the component type it's based on
booleanArrayType = addArrayType(booleanType, Slot_BooleanRef, !HEAP_STORED_ARRAY, BooleanArray.class); // yes, byteref
byteArrayType = addArrayType(byteType, Slot_ByteRef, !HEAP_STORED_ARRAY, ByteArray.class);
shortArrayType = addArrayType(shortType, Slot_ShortRef, !HEAP_STORED_ARRAY, ShortArray.class);
longArrayType = addArrayType(longType, Slot_LongRef, !HEAP_STORED_ARRAY, LongArray.class);
doubleArrayType = addArrayType(doubleType, Slot_DoubleRef, !HEAP_STORED_ARRAY, DoubleArray.class);
// Sofa Stuff
sofaType = new TypeImpl(CAS.TYPE_NAME_SOFA, this, topType, Sofa.class);
sofaNum = (FeatureImpl) addFeature(CAS.FEATURE_BASE_NAME_SOFANUM, sofaType, intType, false);
sofaId = (FeatureImpl) addFeature(CAS.FEATURE_BASE_NAME_SOFAID, sofaType, stringType, false);
sofaMime = (FeatureImpl) addFeature(CAS.FEATURE_BASE_NAME_SOFAMIME, sofaType, stringType, false);
// Type localSofa = addType(CAS.TYPE_NAME_LOCALSOFA, sofa);
sofaArray = (FeatureImpl) addFeature(CAS.FEATURE_BASE_NAME_SOFAARRAY, sofaType, topType, true);
sofaString = (FeatureImpl) addFeature(CAS.FEATURE_BASE_NAME_SOFASTRING, sofaType, stringType, false);
// Type remoteSofa = addType(CAS.TYPE_NAME_REMOTESOFA, sofa);
sofaUri = (FeatureImpl) addFeature(CAS.FEATURE_BASE_NAME_SOFAURI, sofaType, stringType, false);
// Annotations
annotBaseType = new TypeImpl_annotBase(CAS.TYPE_NAME_ANNOTATION_BASE, this, topType, AnnotationBase.class);
annotBaseSofaFeat = (FeatureImpl) addFeature(CAS.FEATURE_BASE_NAME_SOFA, annotBaseType, sofaType, false);
annotType = new TypeImpl_annot(CAS.TYPE_NAME_ANNOTATION, this, annotBaseType, Annotation.class);
startFeat = (FeatureImpl) addFeature(CAS.FEATURE_BASE_NAME_BEGIN, annotType, intType, false);
endFeat = (FeatureImpl) addFeature(CAS.FEATURE_BASE_NAME_END, annotType, intType, false);
docType = new TypeImpl_annot(CAS.TYPE_NAME_DOCUMENT_ANNOTATION, this, annotType, Annotation.class);
langFeat = (FeatureImpl) addFeature(CAS.FEATURE_BASE_NAME_LANGUAGE, docType, stringType, false);
// fsArrayListType = new TypeImpl(CAS.TYPE_NAME_FS_ARRAY_LIST, this, topType);
// addFeature(CAS.FEATURE_BASE_NAME_FS_ARRAY, fsArrayListType, fsArrayType);
//
// intArrayListType = new TypeImpl(CAS.TYPE_NAME_INT_ARRAY_LIST, this, topType);
// addFeature(CAS.FEATURE_BASE_NAME_INT_ARRAY, intArrayListType, intArrayType);
//
// fsHashSetType = new TypeImpl(CAS.TYPE_NAME_FS_HASH_SET, this, topType);
// addFeature(CAS.FEATURE_BASE_NAME_FS_ARRAY, fsHashSetType, fsArrayType);
// javaObjectType = new TypeImpl_javaObject(CAS.TYPE_NAME_JAVA_OBJECT, this, topType, Object.class);
// javaObjectArrayType = addArrayType(javaObjectType, null, HEAP_STORED_ARRAY, JavaObjectArray.class);
arrayName2ComponentType.put(CAS.TYPE_NAME_FS_ARRAY, topType);
arrayName2ComponentType.put(CAS.TYPE_NAME_BOOLEAN_ARRAY, booleanType);
arrayName2ComponentType.put(CAS.TYPE_NAME_BYTE_ARRAY, byteType);
arrayName2ComponentType.put(CAS.TYPE_NAME_SHORT_ARRAY, shortType);
arrayName2ComponentType.put(CAS.TYPE_NAME_INTEGER_ARRAY, intType);
arrayName2ComponentType.put(CAS.TYPE_NAME_FLOAT_ARRAY, floatType);
arrayName2ComponentType.put(CAS.TYPE_NAME_LONG_ARRAY, longType);
arrayName2ComponentType.put(CAS.TYPE_NAME_DOUBLE_ARRAY, doubleType);
arrayName2ComponentType.put(CAS.TYPE_NAME_STRING_ARRAY, stringType);
// arrayName2ComponentType.put(CAS.TYPE_NAME_JAVA_OBJECT_ARRAY, javaObjectType);
// // initialize the decompiler settings to read the class definition
// // from the classloader of this class. Needs to be fixed to work with PEARs
// // or custom UIMA class loaders.
//
// if (IS_DECOMPILE_JCAS) {
// ITypeLoader tl = new ITypeLoader() {
//
// @Override
// public boolean tryLoadType(String internalName, Buffer buffer) {
//
// // get the classloader to use to read the class as a resource
// ClassLoader cl = this.getClass().getClassLoader();
//
// // read the class as a resource, and put into temporary byte array output stream
// // because we need to know the length
//
// internalName = internalName.replace('.', '/') + ".class";
// InputStream stream = cl.getResourceAsStream(internalName);
// if (stream == null) {
// return false;
// }
// ByteArrayOutputStream baos = new ByteArrayOutputStream(1024 * 16);
// byte[] b = new byte[1024 * 16];
// int numberRead;
// try {
// while (0 <= (numberRead = stream.read(b))){
// baos.write(b, 0, numberRead);
// }
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
//
// // Copy result (based on length) into output buffer spot
// int length = baos.size();
// b = baos.toByteArray();
// buffer.reset(length);
// System.arraycopy(b, 0, buffer.array(), 0, length);
//
// return true;
// }
// };
// decompilerSettings.setTypeLoader(tl);
// }
// Lock individual types.
setTypeFinal(intType);
setTypeFinal(floatType);
setTypeFinal(stringType);
topType.setFeatureFinal();
setTypeFinal(arrayBaseType);
setTypeFinal(fsArrayType);
setTypeFinal(intArrayType);
setTypeFinal(floatArrayType);
setTypeFinal(stringArrayType);
setTypeFinal(sofaType);
setTypeFinal(byteType);
setTypeFinal(booleanType);
setTypeFinal(shortType);
setTypeFinal(longType);
setTypeFinal(doubleType);
setTypeFinal(booleanArrayType);
setTypeFinal(byteArrayType);
setTypeFinal(shortArrayType);
setTypeFinal(longArrayType);
setTypeFinal(doubleArrayType);
// setTypeFinal(javaObjectArrayType);
setTypeFinal(fsListType);
setTypeFinal(floatListType);
setTypeFinal(stringListType);
setTypeFinal(intListType);
setTypeFinal(fsEListType);
setTypeFinal(floatEListType);
setTypeFinal(stringEListType);
setTypeFinal(intEListType);
setTypeFinal(fsNeListType);
setTypeFinal(floatNeListType);
setTypeFinal(stringNeListType);
setTypeFinal(intNeListType);
topType.setBuiltIn();
listBaseType.setBuiltIn();
fsListType.setBuiltIn();
fsEListType.setBuiltIn();
fsNeListType.setBuiltIn();
floatListType.setBuiltIn();
floatEListType.setBuiltIn();
floatNeListType.setBuiltIn();
intListType.setBuiltIn();
intEListType.setBuiltIn();
intNeListType.setBuiltIn();
stringListType.setBuiltIn();
stringEListType.setBuiltIn();
stringNeListType.setBuiltIn();
annotType.setBuiltIn();
annotBaseType.setBuiltIn();
// setTypeFinal(fsArrayListType);
// setTypeFinal(intArrayListType);
// setTypeFinal(fsHashSetType);
listBaseType.setFeatureFinal();
fsListType.setFeatureFinal();
fsEListType.setFeatureFinal();
fsNeListType.setFeatureFinal();
floatListType.setFeatureFinal();
floatEListType.setFeatureFinal();
floatNeListType.setFeatureFinal();
intListType.setFeatureFinal();
intEListType.setFeatureFinal();
intNeListType.setFeatureFinal();
stringListType.setFeatureFinal();
stringEListType.setFeatureFinal();
stringNeListType.setFeatureFinal();
annotType.setFeatureFinal();
annotBaseType.setFeatureFinal();
// fsArrayListType.setFeatureFinal();
// intListType.setFeatureFinal();
// fsHashSetType.setFeatureFinal();
// allTypesForByteCodeGen = new TypeImpl[] {
// booleanType,
// byteType,
// shortType,
// intType,
// floatType,
// longType,
// doubleType,
//
// stringType,
// topType,
// javaObjectType,
//
// booleanArrayType,
// byteArrayType,
// shortArrayType,
// intArrayType,
// floatArrayType,
// longArrayType,
// doubleArrayType,
// stringArrayType,
// topArrayType,
// javaObjectArrayType};
}
// Some implementation helpers for users of the type system.
final int getSmallestType() {
return LEAST_TYPE_CODE;
}
final int getSmallestFeature() {
return LEAST_FEATURE_CODE;
}
public final int getTypeArraySize() {
return types.size(); // getNumberOfTypes() + getSmallestType();
}
public Vector<Feature> getIntroFeatures(Type type) {
Vector<Feature> feats = new Vector<Feature>();
List<Feature> appropFeats = type.getFeatures();
final int max = appropFeats.size();
Feature feat;
for (int i = 0; i < max; i++) {
feat = appropFeats.get(i);
if (feat.getDomain() == type) {
feats.add(feat);
}
}
return feats;
}
@Override
public Type getParent(Type t) {
return ((TypeImpl) t).getSuperType();
}
// int ll_computeArrayParentFromComponentType(int componentType) {
// if (ll_isPrimitiveType(componentType) ||
// // note: not using top - until we can confirm this is set
// // in all cases
// (ll_getTypeForCode(componentType).getName().equals(TypeSystem.TYPE_NAME_TOP))) {
// return arrayBaseTypeCode;
// }
// // is a subtype of FSArray.
// // note: not using this.fsArray - until we can confirm this is set in
// // all cases
// return fsArrayTypeCode;
// // return ll_getArrayType(ll_getParentType(componentType));
// }
// /**
// * Check if feature is appropriate for type (i.e., type is subsumed by domain type of feature).
// * @param type -
// * @param feat -
// * @return true if feature is appropriate for type (i.e., type is subsumed by domain type of feature).
// */
// public boolean isApprop(int type, int feat) {
//
// return subsumes(intro(feat), type);
// }
public final int getLargestTypeCode() {
return getNumberOfTypes();
}
/**
*
* @param typecode to check if it's in the range of valid type codes
* @return true if it is
*/
public boolean isType(int typecode) {
return ((typecode >= LEAST_TYPE_CODE) && (typecode <= getLargestTypeCode()));
}
/**
* Get a type object for a given name.
*
* @param typeName
* The name of the type.
* @return A type object, or <code>null</code> if no such type exists.
*/
@Override
public TypeImpl getType(String typeName) {
return typeName2TypeImpl.get(typeName);
}
/**
* Get an feature object for a given code.
*
* @param featCode
* The code of the feature.
* @return A feature object, or <code>null</code> if no such feature exists.
*/
// public Feature getFeature(int featCode) {
// return (Feature) this.features.get(featCode);
// }
/**
* Get an feature object for a given name.
*
* @param featureName
* The name of the feature.
* @return An feature object, or <code>null</code> if no such feature exists.
*/
@Override
public FeatureImpl getFeatureByFullName(String featureName) {
int split = featureName.indexOf(TypeSystem.FEATURE_SEPARATOR);
return getFeature(featureName.substring(0, split), featureName.substring(split + 1));
}
/**
* For component xyz, returns "xyz[]"
* @param componentType the component type
* @return the name of the component + []
*/
private static final String getArrayTypeName(String typeName) {
final String arrayTypeName = builtInArrayComponentName2ArrayTypeName.get(typeName);
return (null == arrayTypeName) ? typeName + ARRAY_TYPE_SUFFIX : arrayTypeName;
}
static final String getArrayComponentName(String arrayTypeName) {
return arrayTypeName.substring(0, arrayTypeName.length() - 2);
}
static boolean isArrayTypeNameButNotBuiltIn(String typeName) {
return typeName.endsWith(ARRAY_TYPE_SUFFIX);
}
// private final TypeImpl getBuiltinArrayComponent(String typeName) {
// // if typeName is not contained in the map, the "get" returns null
// // if (arrayName2ComponentType.containsKey(typeName)) {
// return arrayName2ComponentType.get(typeName);
// // }
// // return null;
// }
void newTypeChecks(String typeName, Type superType) {
if (typeName.endsWith(ARRAY_TYPE_SUFFIX)) {
checkTypeSyntax(typeName.substring(0, typeName.length() - 2));
} else {
if (this.locked) {
throw new CASAdminException(CASAdminException.TYPE_SYSTEM_LOCKED);
}
if (superType != null && superType.isInheritanceFinal() ) {
throw new CASAdminException(CASAdminException.TYPE_IS_INH_FINAL, superType);
}
checkTypeSyntax(typeName);
}
}
void newTypeCheckNoInheritanceFinalCheck(String typeName, Type superType) {
if (this.locked) {
throw new CASAdminException(CASAdminException.TYPE_SYSTEM_LOCKED);
}
checkTypeSyntax(typeName);
}
/**
* Method checkTypeSyntax.
*
* @param typeName
*/
private void checkTypeSyntax(String name) throws CASAdminException {
if (!TypeSystemUtils.isTypeName(name)) {
throw new CASAdminException(CASAdminException.BAD_TYPE_SYNTAX, name);
}
}
/**
* Add a new type to the type system.
* Called to add types for new (not built-in) types,
* except for:
* arrays
* string subtypes
* primitives
*
* All of these have special addType methods
* @param typeName
* The name of the new type.
* @param superType
* The type node under which the new type should be attached.
* @return The new type, or <code>null</code> if <code>typeName</code> is already in use.
*/
public TypeImpl addType(String typeName, Type superType) throws CASAdminException {
newTypeChecks(typeName, superType);
if (null != typeName2TypeImpl.get(typeName)) {
return null;
}
final TypeImpl supertypeimpl = (TypeImpl) superType;
TypeImpl ti = supertypeimpl.isAnnotationType() ?
new TypeImpl_annot (typeName, this, supertypeimpl, Annotation.class) :
supertypeimpl.isAnnotationBaseType() ?
new TypeImpl_annotBase(typeName, this, supertypeimpl, AnnotationBase.class) :
new TypeImpl (typeName, this, supertypeimpl);
return ti;
}
public boolean isInInt(Type rangeType) {
return (rangeType == null)
? false
: (rangeType.isPrimitive() && !subsumes(stringType, rangeType));
}
@Override
public Feature addFeature(String featureName, Type domainType, Type rangeType)
throws CASAdminException {
return addFeature(featureName, domainType, rangeType, true);
}
/**
* @see TypeSystemMgr#addFeature(String, Type, Type)
*/
@Override
public Feature addFeature(String shortFeatName, Type domainType, Type rangeType, boolean multipleReferencesAllowed)
throws CASAdminException {
if (this.locked) {
throw new CASAdminException(CASAdminException.TYPE_SYSTEM_LOCKED);
}
FeatureImpl existingFeature = (FeatureImpl) getFeature(domainType, shortFeatName);
if (existingFeature != null) {
((TypeImpl)domainType).checkExistingFeatureCompatible(existingFeature, rangeType);
TypeImpl highestDefiningType = existingFeature.getHighestDefiningType();
if (highestDefiningType != domainType && subsumes(domainType, highestDefiningType)) {
// never happens in existing test cases 6/2017 schor
Misc.internalError(); // logically can never happen
// Note: The other case, where a type and subtype are defined, and then
// features are added in any order, in particular, a
// supertype feature is added after a subtype feature of the same name/range has been added,
// causes the subtype's feature to be "deleted" and "inherited" instead.
// code: checkAndAdjustFeatureInSubtypes in TypeImpl
// existingFeature.setHighestDefiningType(domainType);
}
return existingFeature;
}
/** Can't add feature to type "{0}" since it is feature final. */
if (domainType.isFeatureFinal()) {
throw new CASAdminException(CASAdminException.TYPE_IS_FEATURE_FINAL, domainType.getName());
}
if (!TypeSystemUtils.isIdentifier(shortFeatName)) {
throw new CASAdminException(CASAdminException.BAD_FEATURE_SYNTAX, shortFeatName);
}
// at end of FeatureImpl constructor, TypeImpl.addFeature is called
// which does checks, calls checkAndAdjustFeatureInSubtypes, etc.
return new FeatureImpl(
(TypeImpl) domainType,
shortFeatName,
(TypeImpl) rangeType,
this,
multipleReferencesAllowed,
getSlotKindFromType(rangeType));
}
/**
* Given a range type, return the corresponding slot kind
* string -> Slot_StrRef, long and double -> ...Ref
* boolean, byte, int, short, float, -> withoutRef
*
* @param rangeType
* @return
*/
static SlotKind getSlotKindFromType(Type rangeType) {
SlotKind slotKind = rangeType.isStringOrStringSubtype()
? Slot_StrRef
: slotKindsForNonArrays.get(rangeType.getName());
return (null == slotKind) ? Slot_HeapRef : slotKind;
}
/**
* Get an iterator over all types, in no particular order.
*
* @return The iterator.
*/
@Override
public Iterator<Type> getTypeIterator() {
// trick to convert List<TypeImpl> to List<Type> with some safety
Iterator<Type> it = Collections.<Type>unmodifiableList(types).iterator();
it.next();
return it;
}
// @Override
// public Iterator<Feature> getFeatures() {
// Iterator<Feature> it = this.features.iterator();
// // The first element is null, so skip it.
// it.next();
// return it;
// }
/**
* Get the top type, i.e., the root of the type system.
*
* @return The top type.
*/
@Override
public TypeImpl getTopType() {
return this.topType;
}
public TypeImpl getTopTypeImpl() {
return this.topType;
}
/**
* Return the list of all types subsumed by the input type. Note: the list does not include the
* type itself.
*
* @param type
* Input type.
* @return The list of types subsumed by <code>type</code>.
*/
@Override
public List<Type> getProperlySubsumedTypes(Type type) {
return ((TypeImpl)type).getAllSubtypes().collect(Collectors.toList());
}
/**
* Get a vector of the types directly subsumed by a given type.
*
* @param type
* The input type.
* @return A vector of the directly subsumed types.
*/
@Override
public Vector<Type> getDirectlySubsumedTypes(Type type) {
return new Vector<Type>(getDirectSubtypes(type));
}
@Override
public List<Type> getDirectSubtypes(Type type) {
TypeImpl ti = (TypeImpl) type;
return Collections.<Type>unmodifiableList(ti.getDirectSubtypes());
}
//
// /**
// *
// * @param type whose direct instantiable subtypes to iterate over
// * @return an iterator over the direct instantiable subtypes
// */
// public Iterator<Type> getDirectSubtypesIterator(final Type type) {
//
// return new Iterator<Type>() {
//
// private IntVector sub = (type.isArray()) ? zeroLengthIntVector : TypeSystemImpl.this.tree.get(((TypeImpl) type).getCode());
// private int pos = 0;
//
// private boolean isTop = (((TypeImpl)type).getCode() == top);
//
// {
// if (isTop) {
// skipOverNonCreatables();
// }
// }
//
// @Override
// public boolean hasNext() {
// return pos < sub.size();
// }
//
// @Override
// public Type next() {
// if (!hasNext()) {
// throw new NoSuchElementException();
// }
// Type result = TypeSystemImpl.this.types.get(sub.get(pos));
// pos++;
// if (isTop) {
// skipOverNonCreatables();
// }
// return result;
// }
//
// @Override
// public void remove() {
// throw new UnsupportedOperationException();
// }
//
// private void skipOverNonCreatables() {
// if (!hasNext()) {
// return;
// }
// int typeCode = sub.get(pos);
// while (! ll_isPrimitiveArrayType(typeCode) &&
// ! casMetadata.creatableType[typeCode]) {
// pos++;
// if (!hasNext()) {
// break;
// }
// typeCode = sub.get(pos);
// }
// }
// };
// }
public boolean directlySubsumes(TypeImpl t1, TypeImpl t2) {
return t1.getDirectSubtypes().contains(t2);
}
/**
* Does one type inherit from the other?
*
* There are two versions.
*
* Fast: but only works after commit: aTypeImplInstance.subsumes(otherTypeImpl)
* Slower: this routine.
* This routine is called from fast one if not committed.
*
* @param superType
* Supertype.
* @param subType
* Subtype.
* @return <code>true</code> iff <code>sub</code> inherits from <code>super</code>.
*/
@Override
public boolean subsumes(Type superType, Type subType) {
if (superType == subType)
return true;
if (isCommitted()) {
return ((TypeImpl)superType).subsumes((TypeImpl)subType);
}
if (superType.isArray()) {
return ((TypeImpl_array)superType).subsumes((TypeImpl)subType); // doesn't need to be committed
}
if (subType == fsArrayType) {
return superType == topType ||
superType == arrayBaseType;
}
if (subType.isArray()) {
// If the subtype is an array, and the supertype is not, then the
// supertype must be top, or the abstract array base.
return ((superType == topType) || (superType == arrayBaseType));
}
return ((TypeImpl)subType).hasSupertype((TypeImpl) superType);
}
// /**
// * Get the overall number of features defined in the type system.
// * @return -
// */
// public int getNumberOfFeatures() {
// if (this.isCommitted()) {
// return this.numFeatureNames;
// }
// return this.featureNameST.size();
// }
/**
* Get the overall number of types defined in the type system.
* @return - the number of types defined in the type system.
*/
public int getNumberOfTypes() {
return types.size() - 1; // because slot 0 is skipped
}
/**
* Get the overall number of features defined in the type system.
* @return - the number of features defined in the type system.
*/
public int getNumberOfFeatures() {
return features.size() - 1; // because slot 0 is skipped
}
///**
//*
//* @param feat -
//* @return the domain type for a feature.
//*/
//public int intro(int feat) {
// return this.intro.get(feat);
//}
//
///**
//* Get the range type for a feature.
//* @param feat -
//* @return -
//*/
//public int range(int feat) {
// return this.featRange.get(feat);
//}
// Unification is trivial, since we don't have multiple inheritance.
public int unify(int t1, int t2) {
if (this.subsumes(t1, t2)) {
return t2;
} else if (this.subsumes(t2, t1)) {
return t1;
} else {
return -1;
}
}
// int addFeature(String shortName, int domain, int range) {
// return addFeature(shortName, domain, range, true);
// }
//
// /**
// * Add a new feature to the type system.
// * @param shortName -
// * @param domain -
// * @param range -
// * @param multiRefsAllowed -
// * @return -
// */
// int addFeature(String shortName, int domain, int range, boolean multiRefsAllowed) {
// // Since we just looked up the domain in the symbol table, we know it
// // exists.
// String name = this.typeNameST.getSymbol(domain) + TypeSystem.FEATURE_SEPARATOR + shortName;
// // Create a list of the domain type and all its subtypes.
// // Type t = getType(domain);
// // if (t == null) {
// // System.out.println("Type is null");
// // }
// TypeImpl domainType = (TypeImpl) ll_getTypeForCode(domain);
// List<Type> typesLocal = getProperlySubsumedTypes(domainType);
// typesLocal.add(ll_getTypeForCode(domain));
// // For each type, check that the feature doesn't already exist.
// int max = typesLocal.size();
// for (int i = 0; i < max; i++) {
// String featureName = (typesLocal.get(i)).getName() + FEATURE_SEPARATOR + shortName;
// if (this.featureMap.containsKey(featureName)) {
// // We have already added this feature. If the range of the
// // duplicate
// // feature is identical, we don't do anything and just return.
// // Else,
// // we throw an exception.
// Feature oldFeature = getFeatureByFullName(featureName);
// Type oldDomain = oldFeature.getDomain();
// Type oldRange = oldFeature.getRange();
// if (range == ll_getCodeForType(oldRange)) {
// return -1;
// }
// CASAdminException e = new CASAdminException(CASAdminException.DUPLICATE_FEATURE);
// e.addArgument(shortName);
// e.addArgument(ll_getTypeForCode(domain).getName());
// e.addArgument(ll_getTypeForCode(range).getName());
// e.addArgument(oldDomain.getName());
// e.addArgument(oldRange.getName());
// throw e;
// }
// } // Add name to symbol table.
// int feat = this.featureNameST.set(name);
// // Add entries for all subtypes.
// for (int i = 0; i < max; i++) {
// this.featureMap.put((typesLocal.get(i)).getName() + FEATURE_SEPARATOR + shortName,
// feat);
// }
// this.intro.add(domain);
// this.featRange.add(range);
// max = this.typeNameST.size();
// for (int i = 1; i <= max; i++) {
// if (subsumes(domain, i)) {
// (this.approp.get(i)).add(feat);
// }
// }
// FeatureImpl fi = new FeatureImpl(feat, name, this, multiRefsAllowed);
// this.features.add(fi);
// domainType.addIntroducedFeature(fi);
// return feat;
// }
/**
* Check if the first argument subsumes the second
* @param superType -
* @param type -
* @return true if first argument subsumes the second
*/
public boolean subsumes(int superType, int type) {
return this.ll_subsumes(superType, type);
}
// private void updateSubsumption(int type, int superType) {
// final int max = this.typeNameST.size();
// for (int i = 1; i <= max; i++) {
// if (subsumes(i, superType)) {
// addSubsubsumption(i, type);
// }
// }
// addSubsubsumption(type, type);
// }
//
// private void addSubsubsumption(int superType, int type) {
// (this.subsumes.get(superType)).set(type);
// }
//
// private void newType() {
// // The assumption for the implementation is that new types will
// // always be added at the end.
// this.tree.add(new IntVector());
// this.subsumes.add(new BitSet());
// this.approp.add(new IntVector());
// }
// Only used for serialization code.
// SymbolTable getTypeNameST() {
// return this.typeNameST;
// }
//
// private final String getTypeString(Type t) {
// return t.getName() + " (" + ll_getCodeForType(t) + ")";
// }
//
// private final String getFeatureString(Feature f) {
// return f.getName() + " (" + ll_getCodeForFeature(f) + ")";
// }
/**
* This writes out the type hierarchy in a human-readable form.
*
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("Type System <%,d>:%n", System.identityHashCode(this)));
topType.prettyPrintWithSubTypes(sb, 2); // 2 is indent
return sb.toString();
}
/**
* @see org.apache.uima.cas.admin.TypeSystemMgr#commit()
*/
@Override
public TypeSystemImpl commit() {
return commit(this.getClass().getClassLoader()); // default if not called with a CAS context
}
/**
* @see org.apache.uima.cas.admin.TypeSystemMgr#commit(ClassLoader)
*/
@Override
public TypeSystemImpl commit(ClassLoader cl) {
synchronized(this) {
if (this.locked) {
// is a no-op if already loaded for this Class Loader
// otherwise, need to load and set up generators for this class loader
getGeneratorsForClassLoader(cl, false); // false - is not pear
return this; // might be called multiple times, but only need to do once
}
// because subsumes depends on it
// and generator initialization uses subsumes
// this.numCommittedTypes = this.getNumberOfTypes(); // do before
// this.numTypeNames = this.typeNameST.size();
// this.numFeatureNames = this.featureNameST.size();
// this.typeInfoArray = new TypeInfo[getTypeArraySize()];
// cas.commitTypeSystem -
// because it will call the type system iterator
// this.casMetadata.setupFeaturesAndCreatableTypes();
if (!IS_DISABLE_TYPESYSTEM_CONSOLIDATION) {
WeakReference<TypeSystemImpl> prevWr = committedTypeSystems.get(this);
if (null != prevWr) {
TypeSystemImpl prev = prevWr.get();
if (null != prev) {
// the following is a no-op if the generators already set up for this class loader
prev.getGeneratorsForClassLoader(cl, false); // false - is not pear
return prev;
}
}
}
topType.computeDepthFirstCode(1); // fixes up ordering, supers before subs. also sets hasRef.
computeFeatureOffsets(topType, 0);
// if (IS_DECOMPILE_JCAS) {
// synchronized(GLOBAL_TYPESYS_LOCK) {
// for(Type t : getAllTypes()) {
// decompile(t);
// }
// }
// }
type2jcci = FSClassRegistry.get_className_to_jcci(cl, false); // is not pear
lookup = FSClassRegistry.getLookup(cl);
cl_for_commit = cl;
computeAdjustedFeatureOffsets(topType); // must preceed the FSClassRegistry JCas stuff below
// Load all the available JCas classes (if not already loaded).
// Has to follow above, because information computed above is used when
// loading and checking JCas classes
// not done here, done in caller (CASImpl commitTypeSystem),
// when it gets the generators for the class loader for this type system for the first time.
// fsClassRegistry = new FSClassRegistry(this, true);
// FSClassRegistry.loadAtTypeSystemCommitTime(this, true, cl);
this.locked = true;
if (!IS_DISABLE_TYPESYSTEM_CONSOLIDATION) {
committedTypeSystems.put(this, new WeakReference<>(this));
}
// this call is here for the case where a commit happens, but no subsequent
// new CAS or switch classloader call is done. For example, a "reinit" in an existing CAS
// This call internally calls the code to load JCas classes for this class loader.
getGeneratorsForClassLoader(cl, false); // false - is not pear
// FSClassRegistry.loadJCasForTSandClassLoader(this, true, cl);
return this;
} // of sync block
}
/**
* This is the actual offset for the feature, in either the int or ref array
*
* Offsets for super types come before types, because
* multiple subtypes can share the same super type
*
* Offsets due to JCas defined features are set before those from type systems, because
* the same JCas class might be used with different type system,
* and this increases the chance that the assignment is still valid.
*
* Special handling for JCas defined features which are missing in the type system.
* - these are allocated artificial "feature impls", which participate in the offset
* setting, but not in anything else (like serialization)
*
* Special handling for JCas super types which have no corresponding uima types
* - features inferred from these are incorporated for purposes of computing offsets (only), because
* some later type system might have these.
*
* Sets offset into 2 places:
* - the FeatureImpl
* - a set of arrays in the type:
* one mapping offset to featureImpl for refs
* one mapping offset to featureImpl for ints
* one mapping offset to non-fs-refs (for efficiency in enquing these before refs)
*
* also sets the number-of-used slots (int / ref) for allocating, in the type
*
* @param ti - the type
*/
private void computeAdjustedFeatureOffsets(TypeImpl ti) {
List<FeatureImpl> tempIntFis = new ArrayList<>();
List<FeatureImpl> tempRefFis = new ArrayList<>();
List<FeatureImpl> tempNsr = new ArrayList<>();
if (ti != topType) {
// initialize these offset -> fi maps from supertype
ti.initAdjOffset2FeatureMaps(tempIntFis, tempRefFis, tempNsr);
nextI = ti.getSuperType().nbrOfUsedIntDataSlots;
nextR = ti.getSuperType().nbrOfUsedRefDataSlots;
} else {
nextI = 0;
nextR = 0;
}
// all the JCas slots come first, because their offsets can't easily change
// this includes any superClass of a jcas class which is not in this type system
if (! skip_loading_user_jcas) {
JCasClassInfo jcci = getJcci(ti);
if (jcci != null) {
addJCasOffsetsWithSupers(jcci.jcasClass, tempIntFis, tempRefFis, tempNsr);
}
}
for (final FeatureImpl fi : ti.getMergedStaticFeaturesIntroducedByThisType()) {
if (fi.getAdjustedOffset() == -1) {
// wasn't set due to jcas class, above
setFeatureAdjustedOffset(fi, tempIntFis, tempRefFis, tempNsr);
} else {
}
}
ti.nbrOfUsedIntDataSlots = nextI;
ti.nbrOfUsedRefDataSlots = nextR;
ti.setStaticMergedIntFeaturesList((tempIntFis.size() == 0)
? Constants.EMPTY_FEATURE_ARRAY
: tempIntFis.toArray(new FeatureImpl[tempIntFis.size()]));
ti.setStaticMergedRefFeaturesList((tempRefFis.size() == 0)
? Constants.EMPTY_FEATURE_ARRAY
: tempRefFis.toArray(new FeatureImpl[tempRefFis.size()]));
ti.setStaticMergedNonSofaFsRefs ((tempNsr .size() == 0)
? Constants.EMPTY_FEATURE_ARRAY
: tempNsr .toArray(new FeatureImpl[tempNsr .size()]));
// ti.hasOnlyInts = ti.nbrOfUsedIntDataSlots > 0 && ti.nbrOfUsedRefDataSlots == 0;
// ti.hasOnlyRefs = ti.nbrOfUsedRefDataSlots > 0 && ti.nbrOfUsedIntDataSlots == 0;
// ti.hasNoSlots = ti.nbrOfUsedIntDataSlots == 0 && ti.nbrOfUsedRefDataSlots == 0;
for (TypeImpl sub : ti.getDirectSubtypes()) {
computeAdjustedFeatureOffsets(sub);
}
}
/**
* Insures that any super class jcas-defined features,
* not already defined (due to having a corresponding type in this
* type system)
* get their features done first
*
* Walking up the super chain:
* - could encounter a class which has no jcci (it's not a jcas class)
* but has a super class which is one) - so don't stop the up walk.
*
* Stop the up walk when
* - reach the TOP or Object
* - reach a class which has a corresponding uima type (the assumption is that
* this type is a super type
*
* @param ti the type associated with clazz, or null, if none
* @param clazz the class whose supertypes are being scanned. May not be a JCas class
* @param tempIntFis the array of int offsets (refs to feature impls (maybe jcas-only)
* @param tempRefFis the array of ref offsets (refs to feature impls (maybe jcas-only)
* @param tempNsrFis a list of non fs-ref ref values
*/
private void addJCasOffsetsWithSupers(Class<?> clazz,
List<FeatureImpl> tempIntFis,
List<FeatureImpl> tempRefFis,
List<FeatureImpl> tempNsrFis) {
Class<?> superClass = clazz.getSuperclass();
/* **********************
* STOP if get to top *
* **********************/
if (superClass == Object.class) {
return;
}
String superClassName = superClass.getName();
String uimaSuperTypeName = Misc.javaClassName2UimaTypeName(superClassName);
if (this.getType(uimaSuperTypeName) != null) {
/* ****************************
* STOP if get to UIMA type *
* ****************************/
// But process this jcas class level
// then return to recursively process other jcas class levels.
String className = clazz.getName();
String uimaTypeName = Misc.javaClassName2UimaTypeName(className);
TypeImpl ti = this.getType(uimaTypeName);
if (ti != null) {
maybeAddJCasOffsets(ti, tempIntFis, tempRefFis, tempNsrFis);
}
return;
}
// recurse up the superclass chain for all jcci's not having UIMA types
// If they exist, they will have been loaded/created by FSClassRegistry.augmentFeaturesFromJCas
// some intermediate superclasses may not have jccis, just skip over them.
addJCasOffsetsWithSupers(superClass, tempIntFis, tempRefFis, tempNsrFis);
// maybeAddJCasOffsets(clazz, tempIntFis, tempRefFis, tempNsrFis); // already done by above statement
}
/**
*
* @param ti the type having offsets set up for
* @param jcci a corresponding jcci, either for this type or for a super type
* when the super type is not in this uima type system
* @param tempIntFis list to augment with additional slots
* @param tempRefFis list to augment with additional slots
*/
private void maybeAddJCasOffsets(TypeImpl ti,
List<FeatureImpl> tempIntFis,
List<FeatureImpl> tempRefFis,
List<FeatureImpl> tempNsrFis) {
JCasClassInfo jcci = getJcci(ti);
if (null != jcci) { // could be null if class is not a JCas class
addJCasOffsets(jcci, tempIntFis, tempRefFis, tempNsrFis);
}
}
private void addJCasOffsets(JCasClassInfo jcci,
List<FeatureImpl> tempIntFis,
List<FeatureImpl> tempRefFis,
List<FeatureImpl> tempNsrFis) {
List<FeatureImpl> added = IS_TRACE_JCAS_EXPAND ? (new ArrayList<>(0)) : null;
for (FSClassRegistry.JCasClassFeatureInfo jcci_feat : jcci.features) {
TypeImpl rangeType = getType(jcci_feat.uimaRangeName); // could be null
TypeImpl ti = jcci.getUimaType(this); // could be null
FeatureImpl fi = null;
if (ti != null) {
fi = ti.getFeatureByBaseName(jcci_feat.shortName); // could be null
}
if (fi == null) { //
// no feature for this type in this type system, but in the JCas.
// create a FeatureImpl_jcas_only, to hold the offset info to use for
// later in the
// update of the CallSites to install the offsets
fi = new FeatureImpl_jcas_only(jcci_feat.shortName, rangeType);
if (IS_TRACE_JCAS_EXPAND) {
added.add(fi);
}
}
assert fi.getAdjustedOffset() == -1;
setFeatureAdjustedOffset(fi, tempIntFis, tempRefFis, tempNsrFis);
}
if (IS_TRACE_JCAS_EXPAND && added.size() > 0) {
System.out.format("debug trace jcas added: %d slots, %s%n", added.size(),
Misc.ppList(added));
}
}
void setFeatureAdjustedOffset(FeatureImpl fi, List<FeatureImpl> tmpIntFis, List<FeatureImpl> tmpRefFis, List<FeatureImpl> tmpNsr) {
boolean isInt = fi.isInInt;
fi.setAdjustedOffset(isInt ? nextI : nextR);
setOffset2Feat(tmpIntFis, tmpRefFis, tmpNsr, fi, isInt ? (nextI++) : (nextR++));
if (fi.isLongOrDouble) {
nextI ++;
}
}
void setOffset2Feat(
List<FeatureImpl> tempIntFis,
List<FeatureImpl> tempRefFis,
List<FeatureImpl> tempNsr,
FeatureImpl fi,
int next) {
boolean is_jcas_only = fi instanceof FeatureImpl_jcas_only;
if (fi.isInInt) {
// assert tempIntFis.size() == next; // could have added slots from JCas
tempIntFis.add(is_jcas_only ? null : fi);
if (fi.getRangeImpl().isLongOrDouble) {
tempIntFis.add(null);
}
} else {
// assert tempRefFis.size() == next; // could have added slots from JCas
tempRefFis.add(is_jcas_only ? null : fi);
TypeImpl range = fi.getRangeImpl();
if (!is_jcas_only && range.isRefType && range != sofaType) {
tempNsr.add(fi);
}
}
}
private JCasClassInfo getJcci(TypeImpl ti) {
return FSClassRegistry.getOrCreateJCasClassInfo(ti, cl_for_commit, type2jcci, lookup);
}
/**
* Feature "ids" - offsets without adjusting for whether or not they're in the class itself
* @param ti a type to compute these for
* @param next - the next offset
*/
private void computeFeatureOffsets(TypeImpl ti, int next) {
for (FeatureImpl fi : ti.getMergedStaticFeaturesIntroducedByThisType()) {
fi.setOffset(next ++);
}
ti.highestOffset = next - 1; // highest index value, 0 based index
for (TypeImpl sub : ti.getDirectSubtypes()) {
computeFeatureOffsets(sub, next);
}
}
// private void decompile(Type t) {
// String name = t.getName();
// if (name.endsWith(ARRAY_TYPE_SUFFIX)) return;
// if (decompiled.contains(name)) return;
// decompiled.add(name);
//
// if(builtInsWithAltNames.contains(name) )
// name = "org.apache.uima.jcas."+ name.substring(5 /* "uima.".length() */);
//
// String h = System.getProperty(DECOMPILE_JCAS);
// File file = new File(h + "decompiled");
// file.mkdir();
//
// UimaDecompiler ud = new UimaDecompiler(this.getClass().getClassLoader(), file);
// ud.decompileToOutputDirectory(name.replace('.', '/'));
// }
/**
* @see org.apache.uima.cas.admin.TypeSystemMgr#isCommitted()
*/
@Override
public boolean isCommitted() {
return this.locked;
}
/**
* @param typecode for a type
* @return true if type is AnnotationBase or a subtype of it
*/
public boolean isAnnotationBaseOrSubtype(int typecode) {
return isAnnotationBaseOrSubtype(ll_getTypeForCode(typecode));
}
public boolean isAnnotationBaseOrSubtype(Type type) {
return ((TypeImpl)type).isAnnotationBaseType();
}
/**
* @param type a type
* @return true if type is Annotation or a subtype of it
*/
public boolean isAnnotationOrSubtype(Type type) {
return ((TypeImpl)type).isAnnotationType();
}
// dangerous, and not needed, not in any interface
// public void setCommitted(boolean b) {
// this.locked = b;
// }
/*
* @deprecated
*/
@Deprecated
public Feature getFeature(String featureName) {
return getFeatureByFullName(featureName);
}
/**
* @see org.apache.uima.cas.admin.TypeSystemMgr#setFeatureFinal(org.apache.uima.cas.Type)
*/
@Override
public void setFeatureFinal(Type type) {
((TypeImpl) type).setFeatureFinal();
}
/**
* @see org.apache.uima.cas.admin.TypeSystemMgr#setInheritanceFinal(org.apache.uima.cas.Type)
*/
@Override
public void setInheritanceFinal(Type type) {
((TypeImpl) type).setInheritanceFinal();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.TypeSystem#getTypeNameSpace(java.lang.String)
*/
@Override
public TypeNameSpace getTypeNameSpace(String name) {
if (!TypeSystemUtils.isTypeNameSpaceName(name)) {
return null;
}
return new TypeNameSpaceImpl(name, this);
}
/**
* @see TypeSystem#getArrayType(Type)
* @param componentType
* The type of the elements of the resulting array type. This can be any type, even
* another array type.
* @return The array type with the corresponding component type.
* If it doesn't exist, a new TypeImplArray is created for it.
*/
@Override
public Type getArrayType(Type componentType) {
TypeImpl ti = (TypeImpl) arrayComponentTypeToArrayType.get(componentType);
if (null == ti) {
// This path only happens when
// a Feature is declared to be a non-built-in (and therefore non-primitive) array
// that is, an FsArray of another declared uima type.
ti = addArrayType(componentType, getSlotKindFromType(componentType), HEAP_STORED_ARRAY, FSArray.class);
}
return ti;
}
/**
* @see org.apache.uima.cas.admin.TypeSystemMgr#addStringSubtype
*/
@Override
public Type addStringSubtype(String typeName, String[] stringList) throws CASAdminException {
Set<String> allowedValues = new HashSet<>(Arrays.asList(stringList));
TypeImpl supertype = this.stringType;
// Check type name syntax.
checkTypeSyntax(typeName);
TypeImpl existingTi = getType(typeName);
if (existingTi != null) {
if (!(existingTi instanceof TypeImpl_stringSubtype)) {
throw new CASAdminException(CASAdminException.STRING_SUBTYPE_REDEFINE_NAME_CONFLICT,
typeName, existingTi.toString());
}
Set<String> existingAllowedValues = ((TypeImpl_stringSubtype) existingTi).getAllowedValues();
if (!existingAllowedValues.equals(allowedValues)) {
// this type is already defined with identical allowed values, return
// existing one
return existingTi;
}
throw new CASAdminException(CASAdminException.STRING_SUBTYPE_CONFLICTING_ALLOWED_VALUES,
typeName,
Misc.addElementsToStringBuilder(new StringBuilder(), existingAllowedValues).toString(),
Misc.addElementsToStringBuilder(new StringBuilder(), allowedValues).toString());
}
// Create the type.
TypeImpl_stringSubtype type = new TypeImpl_stringSubtype(typeName, this, supertype, allowedValues);
type.setFeatureFinal();
type.setInheritanceFinal();
return type;
}
/**
* Add an array type. This is called for builtin array types, and when processing a Feature specification
* that represents an FSArray of a particular type
* @param componentType the component type
* @return a TypeImplArray
*/
TypeImpl_array addArrayType(Type componentType, SlotKind slotKind, boolean isHeapStoredArray, Class<?> javaClass) {
if (isCommitted()) {
throw new CASRuntimeException(CASRuntimeException.ADD_ARRAY_TYPE_AFTER_TS_COMMITTED,
componentType.getName() + TypeSystemImpl.ARRAY_TYPE_SUFFIX);
}
String arrayTypeName = getArrayTypeName(componentType.getName());
// either fsArray or TOP
TypeImpl supertype = computeArrayParentFromComponentType(componentType);
TypeImpl_array ti = new TypeImpl_array(arrayTypeName, (TypeImpl) componentType, this, supertype, slotKind, isHeapStoredArray, javaClass);
this.arrayComponentTypeToArrayType.put(componentType, ti);
// the reverse - going from array type to component type is done via the getComponentType method of TypeImplArray
return ti;
}
// TypeImplList addTypeList(TypeImpl elementType) {
// return new TypeImplList(CAS.TYPE_NAME_LIST, elementType, this, topType);
// }
//
// TypeImplMap addTypeMap(TypeImpl keyType, TypeImpl valueType) {
// return new TypeImplMap(CAS.TYPE_NAME_MAP, keyType, valueType, this, topType);
// }
// /**
// * Used to support generic access to static-compiled features.
// * Return ordered-by-offset array of FeatureImpls of a particular range class
// * @param valueType - one of booleanType, booleanArrayType, stringType, topType, fsArrayType, etc.
// * see list in allTypes1 in TypeSystemImpl.
// * @return a stream of FeatureImpls having a range of the specified type
// */
// public Stream<FeatureImpl> getTypeFeaturesByRangeType(TypeImpl type, TypeImpl range) {
// return type.getFeaturesAsStream().filter(fi -> ((TypeImpl) fi.getRange()).consolidateType(topType, fsArrayType) == range);
// }
private static void setTypeFinal(Type type) {
TypeImpl t = (TypeImpl) type;
t.setFeatureFinal();
t.setInheritanceFinal();
t.setBuiltIn();
}
private FeatureImpl getFeature(String typeName, String featureShortName) {
Type type = getType(typeName);
if (null == type) {
// System.out.println("debug - get feature for typename: " + typeName + ", feature: " + featureShortName
// + " returned null when getting the type.");
return null;
}
return getFeature(getType(typeName), featureShortName);
}
private FeatureImpl getFeature(Type type, String featureShortName) {
return ((TypeImpl)type).getFeatureByBaseName(featureShortName);
}
/**
* @param ti the type
* @param featureShortName the name of the feature
* @return the offset in the storage array for this feature
*/
public int getFeatureOffset(TypeImpl ti, String featureShortName) {
FeatureImpl fi = (FeatureImpl) ti.getFeatureByBaseName(featureShortName);
return fi.getOffset();
}
// public TypeImpl[] getAllTypesForByteCodeGen() {
// return allTypesForByteCodeGen;
// }
//
//
// /**
// * Each instance holds info needed in binary serialization
// * of data for a particular type
// */
// class TypeInfo {
// // constant data about a particular type
// public final TypeImpl type; // for debug
// /**
// * Array of slot kinds; index 0 is for 1st slot after feature code, length = number of slots excluding type code
// */
// public final SlotKind[] slotKinds;
// public final int[] strRefOffsets;
//
// public final boolean isArray;
// public final boolean isHeapStoredArray; // true if array elements are
// // stored on the main heap
//
// public TypeInfo(TypeImpl type) {
//
// this.type = type;
// List<Feature> features = type.getFeatures();
//
// isArray = type.isArray(); // feature structure array types named
// // type-of-fs[]
// isHeapStoredArray = (type == intArrayType) || (type == floatArrayType)
// || (type == fsArrayType) || (type == stringArrayType)
// || (TypeSystemImpl.isArrayTypeNameButNotBuiltIn(type.getName()));
//
// final ArrayList<Integer> strRefsTemp = new ArrayList<Integer>();
// // set up slot kinds
// if (isArray) {
// // slotKinds has 2 slots: 1st is for array length, 2nd is the slotkind
// // for the array element
// SlotKind arrayKind;
// if (isHeapStoredArray) {
// if (type == intArrayType) {
// arrayKind = Slot_Int;
// } else if (type == floatArrayType) {
// arrayKind = Slot_Float;
// } else if (type == stringArrayType) {
// arrayKind = Slot_StrRef;
// } else {
// arrayKind = Slot_HeapRef;
// }
// } else {
//
// // array, but not heap-store-array
// if (type == booleanArrayType || type == byteArrayType) {
// arrayKind = Slot_ByteRef;
// } else if (type == shortArrayType) {
// arrayKind = Slot_ShortRef;
// } else if (type == longArrayType) {
// arrayKind = Slot_LongRef;
// } else if (type == doubleArrayType) {
// arrayKind = Slot_DoubleRef;
// } else {
// throw new RuntimeException("never get here");
// }
// }
//
// slotKinds = new SlotKind[] { Slot_ArrayLength, arrayKind };
// strRefOffsets = INT0;
//
// } else {
//
// // set up slot kinds for non-arrays
// ArrayList<SlotKind> slots = new ArrayList<SlotKind>();
// int i = -1;
// for (Feature feat : features) {
// i++;
// TypeImpl slotType = (TypeImpl) feat.getRange();
//
// if (slotType == stringType || (slotType instanceof TypeImpl_string)) {
// slots.add(Slot_StrRef);
// strRefsTemp.add(i + 1); // first feature is offset 1 from fs addr
// } else if (slotType == intType) {
// slots.add(Slot_Int);
// } else if (slotType == booleanType) {
// slots.add(Slot_Boolean);
// } else if (slotType == byteType) {
// slots.add(Slot_Byte);
// } else if (slotType == shortType) {
// slots.add(Slot_Short);
// } else if (slotType == floatType) {
// slots.add(Slot_Float);
// } else if (slotType == longType) {
// slots.add(Slot_LongRef);
// } else if (slotType == doubleType) {
// slots.add(Slot_DoubleRef);
// } else {
// slots.add(Slot_HeapRef);
// }
// } // end of for loop
// slotKinds = slots.toArray(new SlotKind[slots.size()]);
// // convert to int []
// final int srlength = strRefsTemp.size();
// if (srlength > 0) {
// strRefOffsets = new int[srlength];
// for (int j = 0; j < srlength; j++) {
// strRefOffsets[j] = strRefsTemp.get(j);
// }
// } else {
// strRefOffsets = INT0;
// }
// }
// }
//
// /**
// * @param offset 0 = typeCode, 1 = first feature, ...
// * @return
// */
// SlotKind getSlotKind(int offset) {
// if (0 == offset) {
// return Slot_TypeCode;
// }
// return slotKinds[offset - 1];
// }
//
// @Override
// public String toString() {
// return type.toString();
// }
// }
//
// TypeInfo getTypeInfo(int typeCode) {
// if (null == typeInfoArray[typeCode]) {
// TypeImpl type = (TypeImpl) ll_getTypeForCode(typeCode);
//// if (null == type) {
//// diagnoseBadTypeCode(typeCode);
//// }
// typeInfoArray[typeCode] = new TypeInfo(type);
// }
// return typeInfoArray[typeCode];
// }
// // debugging
// private void diagnoseBadTypeCode(int typeCode) {
// System.err.format("Bad type code %,d passed to TypeSystem.getTypeInfo, largest type code is %,d, size of types list is %,d%n",
// typeCode, getLargestTypeCode(), types.size());
// System.err.println(this.toString());
// System.err.format("Type in types: %s%n", types.get(typeCode));
// throw new RuntimeException();
// }
/*********************************************************
* Type Mapping Objects
* used in compressed binary (de)serialization
* These are in an identity map, key = target type system
*
* Threading: this map is used by multiple threads
*
* Key = target type system, via a weak reference.
* Automatically cleared via WeakHashMap
*
* The map itself is not synchronized, because all accesses to it are
* from the synchronized getTypeSystemMapper method
*********************************************************/
public final Map<TypeSystemImpl, CasTypeSystemMapper> typeSystemMappers =
new WeakHashMap<TypeSystemImpl, CasTypeSystemMapper>();
synchronized CasTypeSystemMapper getTypeSystemMapper(TypeSystemImpl tgtTs) {
CasTypeSystemMapper ctsm = getTypeSystemMapperInner(tgtTs);
if (null == ctsm || ctsm.isEqual()) { // if the mapper is for this type system
return null;
}
return ctsm;
}
synchronized CasTypeSystemMapper getTypeSystemMapperInner(TypeSystemImpl tgtTs) {
if ((null == tgtTs) || (this == tgtTs)) {
return null; // conventions for no type mapping
}
CasTypeSystemMapper m = typeSystemMappers.computeIfAbsent(tgtTs,
key -> new CasTypeSystemMapper(this, tgtTs));
return m;
}
// /**
// * @param otherTs type system to compare to this one
// * @return true if one or more identically named features have differently named ranges
// */
// public boolean isRangeCheckNeeded(TypeSystemImpl otherTs) {
// if (this == otherTs) {
// return false;
// }
// final List<Feature> smallerList;
// if (features.size() > otherTs.features.size()) {
// smallerList = otherTs.features;
// otherTs = this;
// } else {
// smallerList = features;
// }
//
// for (int i = smallerList.size() - 1; i > 0; i--) { // position 0 is null
// final Feature f1 = smallerList.get(i);
// final Feature f2 = otherTs.getFeatureByFullName(f1.getName());
// if (f2 == null) {
// continue;
// }
// if (!f1.getRange().getName().equals(f2.getRange().getName())) {
// return true;
// }
// }
// return false;
// }
//
/****************************************************************
* Low Level APIs that use type codes and feature codes *
* These are less efficient in V3, and should be replaced where *
* possible with standard non-low-level access *
* **************************************************************
*/
/**
*
* @param typeCode of some type
* @return the type code of the parent type
*/
@Override
public int ll_getParentType(int typeCode) {
if (typeCode == 1) {
return 0;
}
return types.get(typeCode).getSuperType().getCode();
}
/**
* Get an array of the appropriate features for this type.
*/
@Override
public int[] ll_getAppropriateFeatures(int typecode) {
if (!isType(typecode)) {
return null;
}
return types.get(typecode).getFeaturesAsStream().mapToInt(FeatureImpl::getCode).toArray();
}
@Override
public boolean ll_subsumes(int superType, int type) {
return subsumes(types.get(superType), types.get(type));
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.impl.LowLevelTypeSystem#ll_getCodeForTypeName(java.lang.String)
*/
@Override
public int ll_getCodeForTypeName(String typeName) {
if (typeName == null) {
throw new NullPointerException();
}
TypeImpl ti = getType(typeName);
return (ti == null) ? LowLevelTypeSystem.UNKNOWN_TYPE_CODE : ti.getCode();
}
/*
* (non-Javadoc)
*
* @see org.apache.uima.cas.impl.LowLevelTypeSystem#ll_getCodeForType(org.apache.uima.cas.Type)
*/
@Override
public int ll_getCodeForType(Type type) {
return ((TypeImpl) type).getCode();
}
@Override
public int ll_getCodeForFeatureName(String featureName) {
if (featureName == null) {
throw new NullPointerException();
}
FeatureImpl fi = (FeatureImpl) getFeatureByFullName(featureName);
if (fi != null) {
return fi.getCode();
}
return UNKNOWN_FEATURE_CODE;
}
@Override
public int ll_getCodeForFeature(Feature feature) {
return ((FeatureImpl) feature).getCode();
}
@Override
public Type ll_getTypeForCode(int typeCode) {
return getTypeForCode(typeCode);
}
public TypeImpl getTypeForCode(int typeCode) {
if (isType(typeCode)) {
return this.types.get(typeCode);
}
return null;
}
public TypeImpl getTypeForCode_checked(int typeCode) {
TypeImpl r = getTypeForCode(typeCode);
if (r == null) {
throw new LowLevelException(LowLevelException.INVALID_TYPECODE, typeCode);
}
return r;
}
/**
* Check if feature is appropriate for type (i.e., type is subsumed by domain type of feature).
* @param typecode -
* @param featcode -
* @return true if feature is appropriate for type (i.e., type is subsumed by domain type of feature).
*/
public boolean isApprop(int typecode, int featcode) {
return ((TypeImpl) ll_getTypeForCode(typecode)).isAppropriateFeature(ll_getFeatureForCode(featcode));
}
/**
* Feature Code to Offset
* Offset has no clear meaning in V3
* @return An offset <code>&gt;0</code> if <code>feat</code> exists; <code>0</code>, else.
*/
int getFeatureOffset(int feat) {
throw new UIMARuntimeException(UIMARuntimeException.NOT_SUPPORTED_NO_HEAP_IN_UIMA_V3);
}
private final int getLargestFeatureCode() {
return this.features.size();
}
final boolean isFeature(int featureCode) {
return ((featureCode > UNKNOWN_FEATURE_CODE) && (featureCode <= getLargestFeatureCode()));
}
@Override
public Feature ll_getFeatureForCode(int featureCode) {
if (isFeature(featureCode)) {
return this.features.get(featureCode);
}
return null;
}
FeatureImpl getFeatureForCode(int featureCode) {
return this.features.get(featureCode);
}
FeatureImpl getFeatureForCode_checked(int featureCode) {
FeatureImpl f = getFeatureForCode(featureCode);
if (null == f) {
throw new LowLevelException(LowLevelException.INVALID_FEATURE_CODE, featureCode);
}
return f;
}
@Override
public int ll_getDomainType(int featureCode) {
return intro(featureCode);
}
@Override
public int ll_getRangeType(int featureCode) {
return range(featureCode);
}
@Override
public LowLevelTypeSystem getLowLevelTypeSystem() {
return this;
}
@Override
public boolean ll_isStringSubtype(int typecode) {
return types.get(typecode).isStringSubtype();
}
/**
* The range type of features may include
* special uima types that are not creatable, such as the primitive ones
* like integer, or string, or subtypes of string.
* Other types are reference types
*/
boolean classifyAsRefType(String name, TypeImpl superType) {
switch(name) {
case CAS.TYPE_NAME_BOOLEAN:
case CAS.TYPE_NAME_BYTE:
case CAS.TYPE_NAME_SHORT:
case CAS.TYPE_NAME_INTEGER:
case CAS.TYPE_NAME_LONG:
case CAS.TYPE_NAME_FLOAT:
case CAS.TYPE_NAME_DOUBLE:
case CAS.TYPE_NAME_STRING:
// case CAS.TYPE_NAME_JAVA_OBJECT:
// case CAS.TYPE_NAME_MAP:
// case CAS.TYPE_NAME_LIST:
return false;
}
// superType is null for TOP, which is a Ref type
if (superType != null && superType.getName().equals(CAS.TYPE_NAME_STRING)) { // can't compare to stringType - may not be set yet
return false;
}
return true;
}
/**
* @param type the type to test
* @return true if it's a reference type - one that can be created as a FeatureStructure
*/
public boolean isRefType(TypeImpl type) {
return type.isRefType;
}
@Override
public boolean ll_isRefType(int typeCode) {
return isRefType(getTypeForCode(typeCode));
}
@Override
public final int ll_getTypeClass(int typeCode) {
if (typeCode == TypeSystemConstants.booleanTypeCode) {
return LowLevelCAS.TYPE_CLASS_BOOLEAN;
}
if (typeCode == TypeSystemConstants.byteTypeCode) {
return LowLevelCAS.TYPE_CLASS_BYTE;
}
if (typeCode == TypeSystemConstants.shortTypeCode) {
return LowLevelCAS.TYPE_CLASS_SHORT;
}
if (typeCode == TypeSystemConstants.intTypeCode) {
return LowLevelCAS.TYPE_CLASS_INT;
}
if (typeCode == TypeSystemConstants.floatTypeCode) {
return LowLevelCAS.TYPE_CLASS_FLOAT;
}
if (typeCode == TypeSystemConstants.longTypeCode) {
return LowLevelCAS.TYPE_CLASS_LONG;
}
if (typeCode == TypeSystemConstants.doubleTypeCode) {
return LowLevelCAS.TYPE_CLASS_DOUBLE;
}
// false if string type code not yet set up (during initialization)
// need this to avoid NPE in subsumes
if ((TypeSystemConstants.stringTypeCode != LowLevelTypeSystem.UNKNOWN_TYPE_CODE) &&
ll_subsumes(TypeSystemConstants.stringTypeCode, typeCode)) {
return LowLevelCAS.TYPE_CLASS_STRING;
}
if (typeCode == TypeSystemConstants.booleanArrayTypeCode) {
return LowLevelCAS.TYPE_CLASS_BOOLEANARRAY;
}
if (typeCode == TypeSystemConstants.byteArrayTypeCode) {
return LowLevelCAS.TYPE_CLASS_BYTEARRAY;
}
if (typeCode == TypeSystemConstants.shortArrayTypeCode) {
return LowLevelCAS.TYPE_CLASS_SHORTARRAY;
}
if (typeCode == TypeSystemConstants.intArrayTypeCode) {
return LowLevelCAS.TYPE_CLASS_INTARRAY;
}
if (typeCode == TypeSystemConstants.floatArrayTypeCode) {
return LowLevelCAS.TYPE_CLASS_FLOATARRAY;
}
if (typeCode == TypeSystemConstants.longArrayTypeCode) {
return LowLevelCAS.TYPE_CLASS_LONGARRAY;
}
if (typeCode == TypeSystemConstants.doubleArrayTypeCode) {
return LowLevelCAS.TYPE_CLASS_DOUBLEARRAY;
}
if (typeCode == TypeSystemConstants.stringArrayTypeCode) {
return LowLevelCAS.TYPE_CLASS_STRINGARRAY;
}
if (ll_isArrayType(typeCode)) {
return LowLevelCAS.TYPE_CLASS_FSARRAY;
}
return LowLevelCAS.TYPE_CLASS_FS;
}
/**
* @see LowLevelTypeSystem#ll_getArrayType(int)
* @param componentTypeCode the type code of the components of the array
* @return the type code of the requested Array type having components of componentTypeCode, or 0
* if the componentTypeCode is invalid.
*/
@Override
public int ll_getArrayType(int componentTypeCode) {
if (!ll_isValidTypeCode(componentTypeCode)) {
return 0;
}
return ((TypeImpl)(getArrayType(types.get(componentTypeCode)))).getCode();
}
/**
* @see LowLevelTypeSystem#ll_isValidTypeCode(int)
*/
@Override
public boolean ll_isValidTypeCode(int typeCode) {
return isType(typeCode);
// return (this.typeNameST.getSymbol(typeCode) != null)
// || this.arrayToComponentTypeMap.containsKey(typeCode);
}
@Override
public boolean ll_isArrayType(int typeCode) {
if (!ll_isValidTypeCode(typeCode)) {
return false;
}
return types.get(typeCode).isArray();
}
@Override
public int ll_getComponentType(int arrayTypeCode) {
final TypeImpl type = types.get(arrayTypeCode);
if (type.isArray()) {
return ((TypeImpl) ((TypeImpl_array)type).getComponentType()).getCode();
}
return UNKNOWN_TYPE_CODE;
}
/* note that subtypes of String are considered primitive */
@Override
public boolean ll_isPrimitiveType(int typeCode) {
return !ll_isRefType(typeCode);
}
@Override
public String[] ll_getStringSet(int typeCode) {
TypeImpl ti = types.get(typeCode);
if (!ti.isStringSubtype()) {
return null;
}
Set<String> allowedValues = ((TypeImpl_stringSubtype)ti).getAllowedValues();
return allowedValues.stream().toArray(i -> new String[i]);
}
@Override
public Iterator<Feature> getFeatures() {
List<Feature> lf = Collections.unmodifiableList(this.features);
Iterator<Feature> it = lf.iterator();
// The first element is null, so skip it.
it.next();
return it;
}
// public List<FeatureImpl> getFeatureImpls() {
// return this.features;
// }
/**
*
* @param feat -
* @return the domain type for a feature.
*/
public int intro(int feat) {
return ((TypeImpl)(this.features.get(feat).getDomain())).getCode();
}
/**
* Get the range type for a feature.
* @param feat -
* @return -
*/
public int range(int feat) {
return ((TypeImpl)(this.features.get(feat).getRange())).getCode();
}
/**
* Given a component type, return the parent type of the corresponding array type,
* without needing the corresponding array type to exist (yet).
* component type -> (member of) array type -> UIMA parent type of that array type.
*
* The UIMA Type parent of an array is either
* ArrayBase (for primitive arrays, plus String[] and TOP[] (see below)
* FsArray - for XYZ[] reference kinds of arrays
*
* The UIMA Type parent chain goes like this:
* primitive_array -> ArrayBase -> TOP (primitive: boolean, byte, short, int, long, float, double, String)
* String[] -> ArrayBase -> TOP
* TOP[] -> ArrayBase -> TOP
*
* XYZ[] -> FSArray -> TOP where XYZ is not a primitive, not String[], not TOP[]
*
* Arrays of TOP are handled differently from XYZ[] because
* - the creation of the FSArray type requires
* -- the creation of TOP[] type, which requires (unless this is done)
* -- the recursive creation of FSArray type - which causes a null pointer exception
*
* Note that the UIMA super chain is not used very much (mainly for subsumption,
* and for this there is special case code anyways), so this doesn't really matter. (2015 Sept)
*
* Note: the super type chain of the Java impl classes varies from the UIMA super type chain.
* It is used to factor out common behavior among classes of arrays.
*
* *********** NOTE: TBD update the rest of this comment for V3 **************
*
* For non-JCas (in V3, this is only the XYZ[] and TOP[] kinds of arrays)
*
* CommonArrayFSImpl [ for arrays stored on the main heap ]
* ArrayFSImpl (for arrays of FS)
* FloatArrayFSImpl
* IntArrayFSImpl
* StringArrayFSImpl
* CommonAuxArrayFSImpl [ for arrays stored in Aux heaps ]
* BooleanArrayFSImpl
* ByteArrayFSImpl
* ShortArrayFSImpl
* LongArrayFSImpl
* DoubleArrayFSImpl
*
* For JCas: The corresponding types have only TOP as their supertypes
* but they implement the nonJCas interfaces for each subtype.
* Those interfaces implement CommonArrayFS interface
*
* @param componentType the UIMA type of the component of the array
* @return the parent type of the corresponding array type
*/
private TypeImpl computeArrayParentFromComponentType(Type componentType) {
if (componentType.isPrimitive() || (componentType == topType)) {
return arrayBaseType;
}
return fsArrayType;
}
// /**
// * Generate the class for the given name. If it refers to super classes not yet loaded, then the act of
// * defining the class will cause these to be loaded too.
// *
// * Called from UIMATypeSystemClassLoader for lazy loading, or
// * from commit via UIMATypeSystemClassLoaderInjector -> generateAndLoadClass, for batch loading
// *
// * @param name the x.y.z.Foo style name of the class to generate
// * @return the generated Class
// */
// public byte[] jcasGenerate(String name) {
// TypeImpl type = getType(name);
// return featureStructureClassGen.createJCasCoverClass(type);
// }
//
// /**
// * Generate the class for the given name. If it refers to super classes not yet loaded, then the act of
// * defining the class will cause these to be loaded too.
// * @param name the x.y.z.Foo style name of the class to generate
// * @return the generated Class
// */
// public byte[] jcas_TypeGenerate(String name) {
// TypeImpl type = getType(name); // name doesn't have the _Type suffix
// return featureStructureClassGen.createJCas_TypeCoverClass(type);
// }
// /**
// *
// * @param name
// * @return true if name is a JCasGen name (_Type suffix removed outside of this routine)
// * need to exclude those names that are built-in because otherwise, a sub class loader will regenerate them
// * and the built-ins need to be shared and not generated
// */
// public boolean isJCasGenerateOnLoad(String name) {
// return !JCasImpl.builtInsWithAltNames.contains(name) && typeName2TypeImpl.containsKey(name);
// }
// /**
// * FunctionalInterface for creating instances of a type.
// * Acts like a Function, taking a JCas arg, and returning an instance of the JCas type.
// * @param jcasClass the class of the JCas type to construct
// * @return a Functional Interface whose apply method takes a JCas and returns a new instance of the class
// */
// private Function<JCas, TOP> getCreator(Class<?> jcasClass) {
// try {
// MethodHandle mh = lookup.findConstructor(jcasClass, MethodType.methodType(void.class, JCas.class));
// MethodType mtConstructor = MethodType.methodType(jcasClass, JCas.class);
//
// return (Function<JCas, TOP>)LambdaMetafactory.metafactory(
// lookup, // lookup context for the constructor
// "apply", // name of the method in the Function Interface
// MethodType.methodType(Function.class), // signature of callsite, return type is functional interface, args are captured args if any
// mtConstructor.generic(), // samMethodType signature and return type of method impl by function object
// mh, // method handle to constructor
// mtConstructor).getTarget().invokeExact();
// } catch (Throwable e) {
// throw new UIMARuntimeException(UIMARuntimeException.INTERNAL_ERROR);
// }
// }
/**
* Convert between fixed JCas class int (set when it is loaded) and
* this type system's TypeImpl.
*
* @param i the index from the typeIndexId of the JCas cover class
* @return - the type impl associated with that JCas cover class
*/
public TypeImpl getJCasRegisteredType(int i) {
TypeImpl ti;
synchronized(jcasRegisteredTypes) {
ti = (i >= jcasRegisteredTypes.size()) ? null : jcasRegisteredTypes.get(i);
}
if (null == ti) {
throwMissingUIMAtype(i);
}
return ti;
}
/**
* For a given JCasRegistry index, that doesn't have a corresponding UIMA type,
* throw an appropriate exception
* @param i - the index in the JCasRegistry
*/
private void throwMissingUIMAtype(int typeindex) {
Class<? extends TOP> cls = JCasRegistry.getClassForIndex(typeindex);
if (cls != null) {
String className = cls.getName();
// System.err.format("Missing UIMA type, JCas Class name: %s, index: %d, jcasRegisteredTypes size: %d%n", className, typeindex, jcasRegisteredTypes.size());
// dumpTypeSystem();
throw new CASRuntimeException(CASRuntimeException.JCAS_TYPE_NOT_IN_CAS, className);
} else {
throw new CASRuntimeException(CASRuntimeException.JCAS_UNKNOWN_TYPE_NOT_IN_CAS);
}
}
// for debugging
public void dumpTypeSystem() {
StringBuilder sb = new StringBuilder();
sb.append("TypeSystem committed?: ").append(isCommitted()).append('\n');
sb.append("jcasRegisteredTypes:\n");
// dump 5 at a time, use temp stringbuilder to avoid issues with users that wrap System.err
synchronized(jcasRegisteredTypes) {
for (int i = 0; i < jcasRegisteredTypes.size(); i++) {
TypeImpl ti = jcasRegisteredTypes.get(i);
sb.append(String.format("%4d: ", i));
sb.append((ti == null) ? "null" : ti.getName());
if (i % 5 == 0) {
sb.append('\n');
}
}
}
System.err.println(sb);
/** debug dump all types **/
sb.setLength(0);
sb.append("Dumping all type names\n");
List<TypeImpl> allTypes = getAllTypes();
int sz = allTypes.size();
for (int i = 0; i < sz;) {
sb.append(String.format("%4d: %-20s ", i, allTypes.get(i++).getName()));
if (i == sz) break;
if (i % 5 == 0) {
sb.append('\n');
}
}
System.err.println(sb);
}
// public FSClassRegistry getFSClassRegistry() {
// return fsClassRegistry;
// }
/**
*
* @param typeIndexID the JCasTypeID for the JCas cover class that will be used when creating instances of ti
* - may be a supertype of ti, if ti has no JCas class itself
* - may be a subtype of the supertype of ti, if ti has no JCas class itself
* @param ti the UIMA type
*/
void setJCasRegisteredType(int typeIndexID, TypeImpl ti) {
// if (typeIndexID == 23) {
// System.out.format("debug typeIndexId = 23, typeImpl = %s%n", ti.getName());
// }
synchronized (jcasRegisteredTypes) {
TypeImpl existing = Misc.getWithExpand(jcasRegisteredTypes, typeIndexID);
if (existing != null) {
if (ti != existing) {
// allowed
if (ti == null) {
Misc.internalError();
}
if (!existing.subsumes(ti)) {
Misc.internalError();
}
}
} else {
jcasRegisteredTypes.set(typeIndexID, ti);
}
}
}
public static final int getTypeClass(TypeImpl ti) {
switch (ti.getCode()) {
case TypeSystemConstants.intTypeCode: return CASImpl.TYPE_CLASS_INT;
case TypeSystemConstants.floatTypeCode: return CASImpl.TYPE_CLASS_FLOAT;
case TypeSystemConstants.stringTypeCode: return CASImpl.TYPE_CLASS_STRING;
case TypeSystemConstants.intArrayTypeCode: return CASImpl.TYPE_CLASS_INTARRAY;
case TypeSystemConstants.floatArrayTypeCode: return CASImpl.TYPE_CLASS_FLOATARRAY;
case TypeSystemConstants.stringArrayTypeCode: return CASImpl.TYPE_CLASS_STRINGARRAY;
case TypeSystemConstants.fsArrayTypeCode: return CASImpl.TYPE_CLASS_FSARRAY;
case TypeSystemConstants.booleanTypeCode: return CASImpl.TYPE_CLASS_BOOLEAN;
case TypeSystemConstants.byteTypeCode: return CASImpl.TYPE_CLASS_BYTE;
case TypeSystemConstants.shortTypeCode: return CASImpl.TYPE_CLASS_SHORT;
case TypeSystemConstants.longTypeCode: return CASImpl.TYPE_CLASS_LONG;
case TypeSystemConstants.doubleTypeCode: return CASImpl.TYPE_CLASS_DOUBLE;
case TypeSystemConstants.booleanArrayTypeCode: return CASImpl.TYPE_CLASS_BOOLEANARRAY;
case TypeSystemConstants.byteArrayTypeCode: return CASImpl.TYPE_CLASS_BYTEARRAY;
case TypeSystemConstants.shortArrayTypeCode: return CASImpl.TYPE_CLASS_SHORTARRAY;
case TypeSystemConstants.longArrayTypeCode: return CASImpl.TYPE_CLASS_LONGARRAY;
case TypeSystemConstants.doubleArrayTypeCode: return CASImpl.TYPE_CLASS_DOUBLEARRAY;
}
if (ti.isStringOrStringSubtype()) {
return CASImpl.TYPE_CLASS_STRING;
}
if (ti.isArray()) {
return CASImpl.TYPE_CLASS_FSARRAY;
}
return CASImpl.TYPE_CLASS_FS;
}
public List<TypeImpl> getAllTypes() {
return types.subList(1, types.size());
}
public static final TypeSystemImpl staticTsi = new TypeSystemImpl();
static {
TypeSystemImpl tsi = staticTsi.commit(); // needed to assign adjusted offsets to the builtins
if (tsi != staticTsi) Misc.internalError();
}
/**
* HashCode and Equals
* used to compare two type system.
* Equal type systems are collapsed into one
*
* Equal means
* Same types
* Type are same if they have the same features and other flags
* Same Features
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((types == null) ? 0 : types.hashCode());
return result;
}
// debug - compare two type systems, print first different type
public static void compareTs(TypeSystem t1, TypeSystem t2) {
TypeSystemImpl ts1 = (TypeSystemImpl) t1;
TypeSystemImpl ts2 = (TypeSystemImpl) t2;
if (ts1.types.size() != ts2.types.size()) {
System.out.format("ts1 size: %,d ts2 size: %d%n", ts1.types.size(), ts2.types.size());
}
for (int i = 1; i < ts1.types.size(); i++) {
if (ts1.types.get(i).hashCode() != ts2.types.get(i).hashCode()) {
System.out.format("ts1 type: %s%n%nts2 type: %s%n", ts1.types.get(i), ts2.types.get(i));
}
}
System.out.println("done");
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TypeSystemImpl other = (TypeSystemImpl) obj;
if (types == null) {
if (other.types != null)
return false;
} else if (!types.equals(other.types))
return false;
return true;
}
// public void installTypeCreator(Class<?> jcasClass) {
// TypeImpl ti = typeName2TypeImpl.get(jcasClass.getName());
// assert (ti != null);
// ti.setCreator(getCreator(jcasClass), get_TypeCreator(jcasClass));
// }
//
// public void install_TypeCreator(Class<?> jcasClass) {
// Type
// }
// Methods to assist users who build type systems programatically and have
// variables referring to Types and Features to update these after a commit
// (in case the commit consolidated type systems).
public TypeImpl refreshType(Type t) {
return getType(t.getName());
}
public FeatureImpl refreshFeature(Feature f) {
return getFeatureByFullName(f.getName());
}
// /**
// * @param typecode the type code
// * @return the generator for the type
// */
// Object getGenerator(int typecode) {
// return jcasClassesInfo[typecode].generator;
// }
// /**
// * @param typecode
// * @return the associated JCas class (may be for a UIMA supertype, is never null)
// */
// Class<?> getJCasClass(int typecode) {
// return jcasClassesInfo[typecode].jcasClass;
// }
/**
* ******** OBSOLETE - only left in for supporting some jcas style in alpha level *************
* This code is run when a JCas class is loaded and resolved, for the first time, as part of type system commit, or
* as part of statically loading the FSClassRegister class (where this is done for all the built-ins, once).
* It looks up the offset value in the type system (via a thread-local)
*
* hidden parameter: threadLocal value: referencing this type
* @param featName -
* @return the offset in the int or ref data arrays for the named feature
*/
// ******** OBSOLETE - only left in for supporting some jcas style in alpha level *************
public static synchronized int getAdjustedFeatureOffset(String featName) {
/* The JCas class being loaded was generated for the "alpha" level of UIMA v3,
* and is not supported for Beta and later levels.
*
* This can be fixed by regenerating this using the current v3 version of UIMA tooling
* (JCasgen, or the migration tooling to migrate from v2).
*/
Logger logger = UIMAFramework.getLogger(TypeSystemImpl.class);
logger.warn(() -> logger.rb_ue(CASRuntimeException.JCAS_ALPHA_LEVEL_NOT_SUPPORTED));
return -1;
}
static int getAdjustedFeatureOffset(TypeImpl type, String featName) {
FeatureImpl fi = type.getFeatureByBaseName(featName);
return (fi == null) ? -1 : fi.getAdjustedOffset();
// if (fi == null) {
// FeatureImpl_jcas_only fi_j = type.getJcasAddedFeature(featName);
// return (fi_j == null) ? -1 : fi_j.getAdjustedOffset();
// }
// return fi.getAdjustedOffset();
}
/**
* When deserializing Xmi and XCAS, Arrays of Feature Structures are encoded as FSArray types, but they
* may have a more restrictive typing, e.g. arrays of Annotation, with the type code of Annotation[].
*
* This is determined by the range type of the feature referring to the array instance.
*
* A fixup is done when one of these feature references is set, that updates the type of the deserialized object
* from FSArray to the most restrictive (in case there are multiple refs) array type.
*/
void fixupFSArrayTypes(TypeImpl featRange, TOP arrayFs) {
if (arrayFs != null && featRange.isTypedFsArray() ) { // https://issues.apache.org/jira/browse/UIMA-5446
if (arrayFs._getTypeImpl().getComponentType().subsumesStrictly(featRange.getComponentType())) {
arrayFs._setTypeImpl(featRange); // replace more general type with more specific type
}
}
}
/**
* Called when switching or initializing CAS's shared-view-data instance of FsGenerator[]
* @param cl the class loader
* @param isPear -
* @return the generators
*/
public FsGenerator3[] getGeneratorsForClassLoader(ClassLoader cl, boolean isPear) {
Map<ClassLoader, FsGenerator3[]> gByC = isPear ? generators4pearsByClassLoader : generatorsByClassLoader;
synchronized (gByC) {
FsGenerator3[] g = gByC.get(cl); // a separate map per type system instance
if (g == null && ! skip_loading_user_jcas) {
g = FSClassRegistry.getGeneratorsForClassLoader(cl, isPear, this);
gByC.put(cl, g);
}
return g;
}
}
/**
* Creates and returns a new MutableCallSite,
// * recording it in list of all callsites for this type, in a map by typename
// *
// * Done this way because
// * - can't be a classloader-wide list of call sites - some might not be associated with this type system
// * - can't be a typesystem-wide list of call sites - the JCas class might be used by multiple type systems
// * and the first one to load it would set this value.
// * - has to be pairs of feature name, call-site, in order to get the value to set, later
// * -- doesn't need to be a hashmap, can be an arraylist of entry
// * Type being loaded may not be known at this point.
* @param clazz the JCas class
* @param featName the short name of the feature
* @return the created callsite
*/
public final static MutableCallSite createCallSite(Class<? extends TOP> clazz, String featName) {
MutableCallSite callSite = new MutableCallSite(MethodType.methodType(int.class));
callSite.setTarget(MHC_MINUS_1); // for error checking
// ArrayList<Entry<String, MutableCallSite>> callSitesForType = FSClassRegistry.callSites_all_JCasClasses.computeIfAbsent(clazz, k -> new ArrayList<>());
// callSitesForType.add(new AbstractMap.SimpleEntry<String, MutableCallSite>(featName, callSite));
return callSite;
}
@Override
public Iterator<Type> iterator() {
return getTypeIterator();
}
public void set_skip_loading_user_jcas(boolean v) {
this.skip_loading_user_jcas = v;
}
// private static boolean isBuiltIn(Class<? extends TOP> clazz) {
// return BuiltinTypeKinds.creatableBuiltinJCasClassNames.contains(clazz.getName());
// }
// /**
// * Get a list of types which have OID feature, filtered down to being just the top-most
// * (in the type hierarchy)
// */
// public List<TypeImpl> getTopOidTypes() {
// List<TypeImpl> r = new ArrayList<>();
//
// outer:
// for (TypeImpl t : types) {
// if (t.featUimaUID != null) {
// for (TypeImpl prev : r) {
// if (prev.subsumes(t)) {
// continue outer;
// }
// }
// r.add(t);
// }
// }
// return r;
// }
}