* @throws ResourceInitializationException
* if an error occurs during modification of the type system
*/
public static void setupTypeSystem(CASMgr aCASMgr, TypeSystemDescription aTypeSystem)
throws ResourceInitializationException {
TypeSystemMgr typeSystemMgr = aCASMgr.getTypeSystemMgr();
if (aTypeSystem != null) {
TypeDescription[] types = aTypeSystem.getTypes();
if (types != null) {
// add all Types first (so that we can handle forward references) - note
// that it isn't guarnanteed that a supertype will occur in the Types list
// before its subtype.
// Build a linked list of type descriptions. We will make multiple passes
// over this, adding types to the CAS and removing them from the linked
// list. We continue until the list is empty or we cannot make any
// progress.
LinkedList<TypeDescription> typeList = new LinkedList<TypeDescription>();
typeList.addAll(Arrays.asList(types));
int numTypes = typeList.size();
int lastNumTypes;
List<TypeDescription> typesInOrderOfCreation = new LinkedList<TypeDescription>();
do {
lastNumTypes = numTypes;
Iterator<TypeDescription> it = typeList.iterator();
while (it.hasNext()) {
TypeDescription curTypeDesc = (TypeDescription) it.next();
String typeName = curTypeDesc.getName();
// type does not exist - add it under the appropriate supertype
String superTypeName = curTypeDesc.getSupertypeName();
if (superTypeName == null) {
throw new ResourceInitializationException(
ResourceInitializationException.NO_SUPERTYPE, new Object[] { typeName,
curTypeDesc.getSourceUrlString() });
}
// Check if it's a built-in type: must not change supertype!
Type builtIn = typeSystemMgr.getType(typeName);
if (builtIn != null) {
if (!superTypeName.equals(typeSystemMgr.getParent(builtIn).getName())) {
throw new ResourceInitializationException(
ResourceInitializationException.REDEFINING_BUILTIN_TYPE, new Object[] {
typeSystemMgr.getParent(builtIn), typeName, superTypeName,
curTypeDesc.getSourceUrlString() });
}
}
Type supertype = typeSystemMgr.getType(superTypeName);
if (supertype != null) {
// supertype is defined, so add to CAS type system
// check for special "enumerated types" that extend String
if (curTypeDesc.getSupertypeName().equals(CAS.TYPE_NAME_STRING)) {
AllowedValue[] vals = curTypeDesc.getAllowedValues();
if (vals == null) {
throw new ResourceInitializationException(
ResourceInitializationException.MISSING_ALLOWED_VALUES, new Object[] {
typeName, curTypeDesc.getSourceUrlString() });
}
String[] valStrs = new String[vals.length];
for (int i = 0; i < valStrs.length; i++) {
valStrs[i] = vals[i].getString();
}
typeSystemMgr.addStringSubtype(typeName, valStrs);
} else // a "normal" type
{
// make sure that allowed values are NOT specified for non-string subtypes
if (curTypeDesc.getAllowedValues() != null
&& curTypeDesc.getAllowedValues().length > 0) {
throw new ResourceInitializationException(
ResourceInitializationException.ALLOWED_VALUES_ON_NON_STRING_TYPE,
new Object[] { typeName, curTypeDesc.getSourceUrlString() });
}
typeSystemMgr.addType(typeName, supertype);
}
// remove from list of type descriptions and add it to the typesInOrderOfCreation list
// for later processing
it.remove();
typesInOrderOfCreation.add(curTypeDesc);
}
}
numTypes = typeList.size();
} while (numTypes > 0 && numTypes != lastNumTypes);
// we quit the above loop either when we've added all types or when
// we went through the entire list without successfully finding any
// supertypes. In the latter case, throw an exception. Since there
// can be more than one such type, we look for one that does not have
// ancestor in the list as it is the likely cause of the issue. The
// implementation of this is not as efficient as it could be but avoids
// issues with cyclic definitions.
for (int i = 0; i < typeList.size(); i++) {
TypeDescription td_i = (TypeDescription) typeList.get(i);
boolean foundSuperType = false;
for (int j = 0; j < typeList.size(); j++) {
if (i == j) {
continue;
}
TypeDescription td_j = (TypeDescription) typeList.get(j);
if (td_j.getName().equals(td_i.getSupertypeName())) {
foundSuperType = true;
break;
}
}
if (!foundSuperType) {
throw new ResourceInitializationException(
ResourceInitializationException.UNDEFINED_SUPERTYPE, new Object[] {
td_i.getSupertypeName(), td_i.getName(), td_i.getSourceUrlString() });
}
}
if (numTypes > 0) {
// We get here in either of two cases: there was only one problematic
// type definition, or there was a cycle.
TypeDescription firstFailed = (TypeDescription) typeList.getFirst();
throw new ResourceInitializationException(
ResourceInitializationException.UNDEFINED_SUPERTYPE, new Object[] {
firstFailed.getSupertypeName(), firstFailed.getName(),
firstFailed.getSourceUrlString() });
}
// now for each type, add its features. We add features to supertypes before subtypes. This
// is done so that
// if we have a duplicate feature name on both a supertype and a subtype, it is added to the
// supertype and then
// ignored when we get to the subtype. Although this is a dubious type system, we support it
// for backwards
// compatibility (but we might want to think about generating a warning).
Iterator<TypeDescription> typeIter = typesInOrderOfCreation.iterator();
while (typeIter.hasNext()) {
TypeDescription typeDesc = (TypeDescription) typeIter.next();
Type type = typeSystemMgr.getType(typeDesc.getName());
// assert type != null;
FeatureDescription[] features = typeDesc.getFeatures();
if (features != null) {
for (int j = 0; j < features.length; j++) {
String featName = features[j].getName();
String rangeTypeName = features[j].getRangeTypeName();
Type rangeType = typeSystemMgr.getType(rangeTypeName);
if (rangeType == null) {
throw new ResourceInitializationException(
ResourceInitializationException.UNDEFINED_RANGE_TYPE, new Object[] {
rangeTypeName, featName, typeDesc.getName(),
features[j].getSourceUrlString() });
}
if (rangeType.isArray()) // TODO: also List?
{
// if an element type is specified, get the specific
// array subtype for that element type
String elementTypeName = features[j].getElementType();
if (elementTypeName != null && elementTypeName.length() > 0) {
Type elementType = typeSystemMgr.getType(elementTypeName);
if (elementType == null) {
throw new ResourceInitializationException(
ResourceInitializationException.UNDEFINED_RANGE_TYPE, new Object[] {
elementTypeName, featName, typeDesc.getName(),
features[j].getSourceUrlString() });
}
rangeType = typeSystemMgr.getArrayType(elementType);
}
}
Boolean multiRefAllowed = features[j].getMultipleReferencesAllowed();
if (multiRefAllowed == null) {
multiRefAllowed = Boolean.FALSE; // default to false if unspecified
}
typeSystemMgr.addFeature(featName, type, rangeType, multiRefAllowed.booleanValue());
}
}
}
}
}