in uimaj-core/src/main/java/org/apache/uima/cas/impl/XCASDeserializer.java [344:564]
private void readFS(final TypeImpl type, Attributes attrs, boolean toIndex)
throws SAXParseException {
final int typecode = type.getCode();
final TOP fs;
if (sofaTypeCode == typecode) {
// Special handling for Sofas
// get SofaID - the view name or the string _InitialView
String sofaID = attrs.getValue(CAS.FEATURE_BASE_NAME_SOFAID);
if (sofaID.equals("_DefaultTextSofaName")) {
sofaID = CAS.NAME_DEFAULT_SOFA;
}
final boolean isInitialView = sofaID.equals(CAS.NAME_DEFAULT_SOFA);
// get sofaNum
String sofaNum = attrs.getValue(CAS.FEATURE_BASE_NAME_SOFANUM);
final int extSofaNum = Integer.parseInt(sofaNum);
// get the sofa's FeatureStructure id
// final int sofaExtId = Integer.parseInt(attrs.getValue(XCASSerializer.ID_ATTR_NAME));
// create some maps to handle v1 format XCAS ...
// ... where the sofa feature of annotations was an int not a ref
// for v1 and v2 formats, create the index map
// ***we assume Sofas are always received in Sofanum order***
// Two scenarios ... the initial view is the first sofa, or not.
// If not, the _indexed values need to be remapped to leave room for the initial view,
// which may or may not be in the received CAS.
if (indexMap.size() == 1) {
if (isInitialView) {
// the first Sofa an initial view
if (extSofaNum == 2) {
// this sofa was mapped to the initial view
indexMap.add(-1); // for this CAS, there should not be a sofanum = 1
indexMap.add(1); // map 2 to 1
nextIndex = 2;
} else {
indexMap.add(1);
nextIndex = 2;
}
} else {
if (extSofaNum > 1) {
// the first Sofa not initial, but sofaNum > 1
// must be a v2 format, and sofaNum better be 2
indexMap.add(1);
assert (extSofaNum == 2);
indexMap.add(2);
nextIndex = 3;
} else {
// must be v1 format
indexMap.add(2);
nextIndex = 3;
}
}
} else {
// this is the case for the 2nd and subsequent Sofas
// if the new Sofa is the initial view, always map to 1
if (isInitialView) {
// the initial view is not the first
// if v2 format, space already reserved in mapping
if (indexMap.size() == extSofaNum) {
// v1 format, add mapping for initial view
indexMap.add(1);
}
} else {
indexMap.add(nextIndex);
nextIndex++;
}
}
// Now update the mapping from annotation int to ref values
if (sofaRefMap.size() == extSofaNum) {
// Sofa received in sofaNum order, add new one
sofaRefMap.add(fsId);
} else if (sofaRefMap.size() > extSofaNum) {
// new Sofa has lower sofaNum than last one
sofaRefMap.set(extSofaNum, fsId);
} else {
// new Sofa has skipped ahead more than 1
sofaRefMap.setSize(extSofaNum + 1);
sofaRefMap.set(extSofaNum, fsId);
}
// get the sofa's mimeType
String sofaMimeType = attrs.getValue(CAS.FEATURE_BASE_NAME_SOFAMIME);
String finalSofaId = sofaID;
fs = maybeCreateWithV2Id(fsId,
() -> cas.createSofa(indexMap.get(extSofaNum), finalSofaId, sofaMimeType));
} else { // not a Sofa
if (type.isAnnotationBaseType()) {
// take pains to create FS in the right view.
// the XCAS external form sometimes uses "sofa" and sometimes uses "_ref_sofa"
// - these have different semantics:
// -- sofa = value is the sofaNum
// -- _ref_sofa = value is the external ID of the associated sofa feature structure
String extSofaNum = attrs.getValue(CAS.FEATURE_BASE_NAME_SOFA);
CAS casView;
if (extSofaNum != null) {
casView = cas.getView((indexMap.size() == 1) ? 1 // case of no Sofa, but view ref =
// 1 = _InitialView
: indexMap.get(Integer.parseInt(extSofaNum)));
} else {
String extSofaRefString = attrs
.getValue(XCASSerializer.REF_PREFIX + CAS.FEATURE_BASE_NAME_SOFA);
if (null == extSofaRefString || extSofaRefString.length() == 0) {
throw createException(XCASParsingException.SOFA_REF_MISSING);
}
casView = cas.getView((Sofa) (fsTree.get(Integer.parseInt(extSofaRefString)).fs));
}
if (type.getCode() == TypeSystemConstants.docTypeCode) {
fs = maybeCreateWithV2Id(fsId, () -> casView.getDocumentAnnotation());
// fs = casView.getDocumentAnnotation();
cas.removeFromCorruptableIndexAnyView(fs, cas.getAddbackSingle());
} else {
fs = maybeCreateWithV2Id(fsId, () -> casView.createFS(type));
if (currentFs instanceof UimaSerializable) {
UimaSerializable ufs = (UimaSerializable) currentFs;
uimaSerializableFixups.add(() -> ufs._init_from_cas_data());
}
}
} else { // not an annotation base
fs = maybeCreateWithV2Id(fsId, () -> cas.createFS(type));
if (currentFs instanceof UimaSerializable) {
UimaSerializable ufs = (UimaSerializable) currentFs;
uimaSerializableFixups.add(() -> ufs._init_from_cas_data());
}
}
}
// Hang on to FS for setting content feature (things coded as child xml elements)
currentFs = fs;
int extId = -1;
IntVector indexRep = new IntVector(1); // empty means not indexed
// @formatter:off
/****************************************************************
* Loop for all feature specs *
* - handle features with _ reserved prefix, including _ref_ *
* - handle features without "_" prefix: *
* - if not Sofa *
****************************************************************/
// @formatter:on
for (int i = 0; i < attrs.getLength(); i++) {
final String attrName = attrs.getQName(i);
String attrValue = attrs.getValue(i);
if (attrName.startsWith(reservedAttrPrefix)) {
if (attrName.equals(XCASSerializer.ID_ATTR_NAME)) {
try {
extId = Integer.parseInt(attrValue);
} catch (NumberFormatException e) {
throw createException(XCASParsingException.ILLEGAL_ID, attrValue);
}
} else if (attrName.equals(XCASSerializer.CONTENT_ATTR_NAME)) {
currentContentFeat = attrValue;
// this.state = CONTENT_STATE; APL-6/28/04 - removed, see below
} else if (attrName.equals(XCASSerializer.INDEXED_ATTR_NAME)) {
// if (attrValue.equals(XCASSerializer.TRUE_VALUE) && toIndex)
String[] arrayvals = parseArray(attrValue);
for (int s = 0; s < arrayvals.length; s++) {
indexRep.add(Integer.parseInt(arrayvals[s]));
}
} else {
handleFeature(type, fs, attrName, attrValue, false);
}
} else {
if (sofaTypeCode == typecode) {
if (attrName.equals(CAS.FEATURE_BASE_NAME_SOFAID)
&& attrValue.equals("_DefaultTextSofaName")) {
// fixup old default Sofa name to new one
attrValue = CAS.NAME_DEFAULT_SOFA;
}
}
if (!type.isAnnotationBaseType() || !attrName.equals(CAS.FEATURE_BASE_NAME_SOFA)) {
// skip the setting the sofa feature for Annotation base subtypes - this is set from the
// view
// otherwise handle the feature
handleFeature(type, fs, attrName, attrValue, false);
}
}
}
if (type.getCode() == TypeSystemConstants.docTypeCode) {
cas.addbackSingle(fs);
}
if (sofaTypeCode == typecode) {
Sofa sofa = (Sofa) fs;
cas.getBaseIndexRepository().addFS(sofa);
CAS view = cas.getView(sofa);
// internal sofaNum == 1 always means initial sofa
if (sofa.getSofaRef() == 1) {
cas.registerInitialSofa();
} else {
// add indexRepo for views other than the initial view
indexRepositories.add(cas.getSofaIndexRepository(sofa));
}
((CASImpl) view).registerView(sofa);
views.add(view);
}
FSInfo fsInfo = new FSInfo(fs, indexRep);
if (extId < 0) {
idLess.add(fsInfo);
} else {
fsTree.put(extId, fsInfo);
}
// Set the state; we're either expecting features, or _content.
// APL - 6/28/04 - even if _content attr is not specified, we can still have content, which
// would
// be assigned to the "value" feature, as per XCAS spec. FEAT_STATE did not really seem to be
// working, anyway.
state = CONTENT_STATE;
// if (this.state != CONTENT_STATE)
// {
// this.state = FEAT_STATE;
// }
}