private void readFS()

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;
      // }
    }