You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2015/11/23 22:32:16 UTC

svn commit: r1715964 [3/3] - in /uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl: XmiCasDeserializer.java XmiCasSerializer.java XmiSerializationSharedData.java

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasSerializer.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasSerializer.java?rev=1715964&r1=1715963&r2=1715964&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasSerializer.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiCasSerializer.java Mon Nov 23 21:32:16 2015
@@ -21,6 +21,7 @@ package org.apache.uima.cas.impl;
 
 import java.io.OutputStream;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -28,9 +29,7 @@ import java.util.Map;
 import org.apache.uima.UIMAFramework;
 import org.apache.uima.UIMARuntimeException;
 import org.apache.uima.UimaContext;
-import org.apache.uima.cas.ByteArrayFS;
 import org.apache.uima.cas.CAS;
-import org.apache.uima.cas.CommonArrayFS;
 import org.apache.uima.cas.Marker;
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.TypeSystem;
@@ -41,6 +40,14 @@ import org.apache.uima.cas.impl.XmiSeria
 import org.apache.uima.internal.util.XmlAttribute;
 import org.apache.uima.internal.util.XmlElementName;
 import org.apache.uima.internal.util.XmlElementNameAndContents;
+import org.apache.uima.jcas.cas.ByteArray;
+import org.apache.uima.jcas.cas.CommonArray;
+import org.apache.uima.jcas.cas.CommonList;
+import org.apache.uima.jcas.cas.FSArray;
+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.util.XMLSerializer;
 import org.xml.sax.Attributes;
 import org.xml.sax.ContentHandler;
@@ -126,6 +133,8 @@ public class XmiCasSerializer {
       SYSTEM_LINE_FEED = (lf == null) ? "\n" : lf;
   }
 
+  public final static char[] INT_TO_HEX = "0123456789ABCDEF".toCharArray();
+  
   private final CasSerializerSupport css = new CasSerializerSupport();
   
   private Map<String, String> nsUriToSchemaLocationMap = null;
@@ -579,10 +588,10 @@ public class XmiCasSerializer {
     }
     
     @Override
-    protected void writeView(int sofaAddr, int[] members) throws Exception {
+    protected void writeView(Sofa sofa, Collection<TOP> members) throws Exception {
       workAttrs.clear();
       // this call should never generate a new XmiId, it should just retrieve the existing one for the sofa
-      String sofaXmiId = cds.getXmiId(sofaAddr);   
+      String sofaXmiId = (sofa == null) ? null : cds.getXmiId(sofa);   
       if (sofaXmiId != null && sofaXmiId.length() > 0) {
         addAttribute(workAttrs, "sofa", sofaXmiId);
       }
@@ -618,7 +627,7 @@ public class XmiCasSerializer {
      * @param isPastFirstElement -
      * @return
      */
-    private StringBuilder writeViewMembers(StringBuilder sb, List<String> members, boolean isPastFirstElement) {
+    private StringBuilder writeViewMembers(StringBuilder sb, Collection<String> members, boolean isPastFirstElement) {
       if (members != null) {
         for (String member : members) {
           if (isPastFirstElement) {
@@ -633,10 +642,10 @@ public class XmiCasSerializer {
     }
 
     
-    private boolean writeViewMembers(StringBuilder sb, int[] members) throws SAXException {
+    private boolean writeViewMembers(StringBuilder sb, Collection<TOP> members) throws SAXException {
       boolean isPastFirstElement = false;
       int nextBreak = (((sb.length() - 1) / CasSerializerSupport.PP_LINE_LENGTH) + 1) * CasSerializerSupport.PP_LINE_LENGTH;
-      for (int member : members) {
+      for (TOP member : members) {
         int xmiId = cds.getXmiIdAsInt(member);
         if (xmiId != 0) { // to catch filtered FS         
           if (isPastFirstElement) {
@@ -654,7 +663,7 @@ public class XmiCasSerializer {
       return isPastFirstElement;
     }
 
-    private void writeViewForDeltas(String kind, int[] deltaMembers) throws SAXException {
+    private void writeViewForDeltas(String kind, Collection<TOP> deltaMembers) throws SAXException {
       StringBuilder sb = new StringBuilder();
       writeViewMembers(sb, deltaMembers);   
       if (sb.length() > 0) {
@@ -663,8 +672,8 @@ public class XmiCasSerializer {
     }
 
     @Override
-    protected void writeView(int sofaAddr, int[] added, int[] deleted, int[] reindexed) throws SAXException {
-      String sofaXmiId = cds.getXmiId(sofaAddr);
+    protected void writeView(Sofa sofa, Collection<TOP> added, Collection<TOP> deleted, Collection<TOP> reindexed) throws SAXException {
+      String sofaXmiId = cds.getXmiId(sofa);
       workAttrs.clear();
       if (sofaXmiId != null && sofaXmiId.length() > 0) {
         addAttribute(workAttrs, "sofa", sofaXmiId);
@@ -693,20 +702,20 @@ public class XmiCasSerializer {
     }        
 
     @Override
-    protected void writeFs(int addr, int typeCode) throws SAXException {
-      writeFsOrLists(addr, typeCode, false);
+    protected void writeFs(TOP fs, int typeCode) throws SAXException {
+      writeFsOrLists(fs, typeCode, false);
     }
 
     @Override
-    protected void writeListsAsIndividualFSs(int addr, int typeCode) throws SAXException {
-      writeFsOrLists(addr, typeCode, true);
+    protected void writeListsAsIndividualFSs(TOP fs, int typeCode) throws SAXException {
+      writeFsOrLists((TOP)fs, typeCode, true);
     }
 
-    private void writeFsOrLists(int addr, int typeCode, boolean isListAsFSs) throws SAXException {
+    private void writeFsOrLists(TOP fs, int typeCode, boolean isListAsFSs) throws SAXException {
       // encode features. this populates the attributes (workAttrs). It also
       // populates the child elements list with features that are to be encoded
       // as child elements (currently required for string arrays).
-      List<XmlElementNameAndContents> childElements = encodeFeatures(addr, workAttrs, isListAsFSs);
+      List<XmlElementNameAndContents> childElements = encodeFeatures(fs, workAttrs, isListAsFSs);
       XmlElementName xmlElementName = cds.typeCode2namespaceNames[typeCode];
       startElement(xmlElementName, workAttrs, childElements.size());
       sendElementEvents(childElements);
@@ -714,21 +723,21 @@ public class XmiCasSerializer {
     }
   
     @Override
-    protected void writeArrays(int addr, int typeCode, int typeClass) throws SAXException {
+    protected void writeArrays(TOP fsArray, int typeCode, int typeClass) throws SAXException {
       XmlElementName xmlElementName = cds.typeCode2namespaceNames[typeCode];
       
-      if (typeClass == LowLevelCAS.TYPE_CLASS_STRINGARRAY) {
+      if (fsArray instanceof StringArray) {
 
         // string arrays are encoded as elements, in case they contain whitespace
         List<XmlElementNameAndContents> childElements = new ArrayList<XmlElementNameAndContents>();
-        stringArrayToElementList("elements", addr, childElements);
+        stringArrayToElementList("elements", (StringArray) fsArray, childElements);
         startElement(xmlElementName, workAttrs, childElements.size());
         sendElementEvents(childElements);
         endElement(xmlElementName);        
 
       } else {
 
-        workAttrs.addAttribute("", "", "elements", "CDATA", arrayToString(addr, typeClass));
+        workAttrs.addAttribute("", "", "elements", "CDATA", arrayToString(fsArray, typeClass));
         startElement(xmlElementName, workAttrs, 0);
         endElement(xmlElementName);      
       }
@@ -852,11 +861,11 @@ public class XmiCasSerializer {
      *         should be added as a child of the FS
      * @throws SAXException passthru
      */
-    private List<XmlElementNameAndContents> encodeFeatures(int addr, AttributesImpl attrs, boolean insideListNode)
+    private List<XmlElementNameAndContents> encodeFeatures(TOP fs, AttributesImpl attrs, boolean insideListNode)
             throws SAXException {
       List<XmlElementNameAndContents> childElements = new ArrayList<XmlElementNameAndContents>();
-      int heapValue = cds.cas.getHeapValue(addr);
-      int[] feats = cds.tsi.ll_getAppropriateFeatures(heapValue);
+//      int heapValue = cds.cas.getHeapValue(addr);
+//      int[] feats = cds.tsi.ll_getAppropriateFeatures(heapValue);
 
       String  attrValue;
       // boolean isSofa = false;
@@ -865,20 +874,18 @@ public class XmiCasSerializer {
       // // set isSofa flag to apply SofaID mapping and to store sofaNum->xmi:id mapping
       // isSofa = true;
       // }
-      for (final int featCode : feats) {
+      for (final FeatureImpl fi : fs._typeImpl.getFeatureImpls()) {
 
         if (cds.isFiltering) {
           // skip features that aren't in the target type system
-          String fullFeatName = cds.tsi.ll_getFeatureForCode(featCode).getName();
+          String fullFeatName = fi.getName();
           if (cds.filterTypeSystem.getFeatureByFullName(fullFeatName) == null) {
             continue;
           }
         }
 
-        final String featName = cds.tsi.ll_getFeatureForCode(featCode).getShortName();
-        final int featAddr = addr + cds.cas.getFeatureOffset(featCode);
-        final int featValRaw = cds.cas.getHeapValue(featAddr);
-        final int featureValueClass = cds.classifyType(cds.tsi.range(featCode));
+        final String featName = fi.getShortName();
+        final int featureValueClass = fi.rangeTypeClass;
         
         switch (featureValueClass) {
         
@@ -889,11 +896,11 @@ public class XmiCasSerializer {
         case LowLevelCAS.TYPE_CLASS_FLOAT:
         case LowLevelCAS.TYPE_CLASS_DOUBLE: 
         case LowLevelCAS.TYPE_CLASS_BOOLEAN:
-          attrValue = cds.cas.getFeatureValueAsString(addr, featCode);
+          attrValue = fs.getFeatureValueAsString(fi);
           break;
         
         case LowLevelCAS.TYPE_CLASS_STRING:
-          attrValue = (featValRaw == CASImpl.NULL) ? null : cds.cas.getStringForCode(featValRaw);  
+          attrValue = fs.getFeatureValueAsString(fi);
           break;
 
           // Arrays
@@ -905,20 +912,20 @@ public class XmiCasSerializer {
         case LowLevelCAS.TYPE_CLASS_LONGARRAY:
         case LowLevelCAS.TYPE_CLASS_DOUBLEARRAY:
         case LowLevelCAS.TYPE_CLASS_FSARRAY: 
-          if (cds.isStaticMultiRef(featCode)) {
-            attrValue = cds.getXmiId(featValRaw);
+          if (cds.isStaticMultiRef(fi.getCode())) {
+            attrValue = cds.getXmiId(fs.getFeatureValue(fi));
           } else {
-            attrValue = arrayToString(featValRaw, featureValueClass);
+            attrValue = arrayToString(fs.getFeatureValue(fi), featureValueClass);
           }
           break;
         
           // special case for StringArrays, which stored values as child elements rather
           // than attributes.
         case LowLevelCAS.TYPE_CLASS_STRINGARRAY: 
-          if (cds.isStaticMultiRef(featCode)) {
-            attrValue = cds.getXmiId(featValRaw);
+          if (cds.isStaticMultiRef(fi.getCode())) {
+            attrValue = cds.getXmiId(fs.getFeatureValue(fi));
           } else {
-            stringArrayToElementList(featName, featValRaw, childElements);
+            stringArrayToElementList(featName, (StringArray) fs.getFeatureValue(fi), childElements);
             attrValue = null;
           }
           break;
@@ -927,41 +934,46 @@ public class XmiCasSerializer {
         case CasSerializerSupport.TYPE_CLASS_INTLIST:
         case CasSerializerSupport.TYPE_CLASS_FLOATLIST:
         case CasSerializerSupport.TYPE_CLASS_FSLIST: 
-          if (insideListNode || cds.isStaticMultiRef(featCode)) {
+          TOP startNode = fs.getFeatureValue(fi);
+          if (insideListNode || cds.isStaticMultiRef(fi.getCode())) {
             // If the feature has multipleReferencesAllowed = true OR if we're already
             // inside another list node (i.e. this is the "tail" feature), serialize as a normal FS.
             // Otherwise, serialize as a multi-valued property.
 //            if (cds.isStaticMultRef(feats[i]) ||
 //                cds.embeddingNotAllowed.contains(featVal) ||
 //                insideListNode) {
-            attrValue = cds.getXmiId(featValRaw);
+            
+            attrValue = cds.getXmiId(startNode);
           } else {
-            attrValue = listToString(featValRaw);
+            attrValue = listToString((CommonList) fs.getFeatureValue(fi));
           }
           break;
         
           // special case for StringLists, which stored values as child elements rather
           // than attributes.
         case CasSerializerSupport.TYPE_CLASS_STRINGLIST: 
-          if (insideListNode || cds.isStaticMultiRef(featCode)) {
-            attrValue = cds.getXmiId(featValRaw);
+          if (insideListNode || cds.isStaticMultiRef(fi.getCode())) {
+            attrValue = cds.getXmiId(fs.getFeatureValue(fi));
           } else {
             // it is not safe to use a space-separated attribute, which would
             // break for strings containing spaces. So use child elements instead.
-            List<String> listOfStrings = cds.listUtils.anyListToStringList(featValRaw, null, cds);
+            StringList stringList = (StringList) fs.getFeatureValue(fi);
+            if (stringList != null) {
+              List<String> listOfStrings = stringList.anyListToStringList(null, cds);
 //              if (array.length > 0 && !arrayAndListFSs.put(featVal, featVal)) {
 //                reportWarning("Warning: multiple references to a ListFS.  Reference identity will not be preserved.");
 //              }
-            for (String string : listOfStrings) {
-              childElements.add(new XmlElementNameAndContents(new XmlElementName(null, featName,
-                      featName), string));
+              for (String string : listOfStrings) {
+                childElements.add(new XmlElementNameAndContents(new XmlElementName(null, featName,
+                        featName), string));
+              }
             }
             attrValue = null;
           }
           break;
         
         default: // Anything that's not a primitive type, array, or list.
-            attrValue = cds.getXmiId(featValRaw);
+            attrValue = cds.getXmiId(fs.getFeatureValue(fi));
             break;
           
         } // end of switch
@@ -973,7 +985,7 @@ public class XmiCasSerializer {
       
       //add out-of-typesystem features, if any
       if (cds.sharedData != null) {
-        OotsElementData oed = cds.sharedData.getOutOfTypeSystemFeatures(addr);
+        OotsElementData oed = cds.sharedData.getOutOfTypeSystemFeatures(fs);
         if (oed != null) {
           //attributes
           Iterator<XmlAttribute> attrIter = oed.attributes.iterator();
@@ -990,30 +1002,32 @@ public class XmiCasSerializer {
     
     /**
      * Create a string to represent array values, embedded format
+     * Not called for StringArray
      * @param addr
      * @param arrayType
      * @return
      * @throws SAXException
      */
-    private String arrayToString(int addr, int arrayType) throws SAXException {
-      if (addr == CASImpl.NULL) {
+    private String arrayToString(TOP fsIn, int arrayType) throws SAXException {
+      if (fsIn == null) {
         return null;
       }
 
       StringBuilder buf = new StringBuilder();
-      final int size = cds.cas.ll_getArraySize(addr);
+      CommonArray fs = (CommonArray) fsIn;
+      final int size = fs.size();
       String elemStr = null;
       
       // FS arrays: handle shared data items
-      if (arrayType == LowLevelCAS.TYPE_CLASS_FSARRAY) {
-        int pos = cds.cas.getArrayStartAddress(addr);
+      if (fs instanceof FSArray) {
         List<XmiArrayElement> ootsArrayElementsList = cds.sharedData == null ? null : 
-                cds.sharedData.getOutOfTypeSystemArrayElements(addr);
+                                                      cds.sharedData.getOutOfTypeSystemArrayElements((FSArray) fs);
         int ootsIndex = 0;
-        for (int j = 0; j < size; j++) {
-          int heapValue = cds.cas.getHeapValue(pos++);
-          
-          if (heapValue == 0) { // null case
+
+        int j = -1;
+        for (TOP elemFS : ((FSArray)fs)._getTheArray()) {
+          j++;
+          if (elemFS == null) { // null case
             // special NULL object with xmi:id=0 is used to represent
             // a null in an FSArray
             elemStr = "0";
@@ -1031,9 +1045,9 @@ public class XmiCasSerializer {
             }
             
           } else {  // not null
-            String xmiId = cds.getXmiId(heapValue);
+            String xmiId = cds.getXmiId(elemFS);
             if (cds.isFiltering) { // return as null any references to types not in target TS
-              String typeName = cds.tsi.ll_getTypeForCode(cds.cas.getHeapValue(addr)).getName();
+              String typeName = elemFS._typeImpl.getName();
               if (cds.filterTypeSystem.getType(typeName) == null) {
                 xmiId = "0";
               }
@@ -1049,57 +1063,56 @@ public class XmiCasSerializer {
         
         return buf.toString();
         
-      } else if (arrayType == LowLevelCAS.TYPE_CLASS_BYTEARRAY) {
+      } else if (fs instanceof ByteArray) {
         
         // special case for byte arrays: serialize as hex digits 
-        ByteArrayFS byteArrayFS = new ByteArrayFSImpl(addr, cds.cas);
-        int len = byteArrayFS.size();
-        for (int i = 0; i < len; i++) {
-          byte b = byteArrayFS.get(i);
-          // this test is necessary to generate a leading zero where necessary
-          if ((b & 0xF0) == 0) {
-            buf.append('0').append(Integer.toHexString(b).toUpperCase());
-          } else {
-            buf.append(Integer.toHexString(0xFF & b).toUpperCase());
-          }
+        byte[] ba = ((ByteArray) fs)._getTheArray();
+        
+        char[] r = new char[ba.length * 2];
+        
+        int i = 0;
+        for (byte b : ba) {
+          r[i++] = INT_TO_HEX[(b & 0xF0) >>> 4];
+          r[i++] = INT_TO_HEX[b & 0x0F];
         }
-        return buf.toString();
+        return new String(r);
       } else {
-        CommonArrayFS fs;
-        String[] fsvalues;
-
-        switch (arrayType) {
-          case LowLevelCAS.TYPE_CLASS_INTARRAY:
-            fs = new IntArrayFSImpl(addr, cds.cas);
-            break;
-          case LowLevelCAS.TYPE_CLASS_FLOATARRAY:
-            fs = new FloatArrayFSImpl(addr, cds.cas);
-            break;
-          case LowLevelCAS.TYPE_CLASS_BOOLEANARRAY:
-            fs = new BooleanArrayFSImpl(addr, cds.cas);
-            break;
-          case LowLevelCAS.TYPE_CLASS_SHORTARRAY:
-            fs = new ShortArrayFSImpl(addr, cds.cas);
-            break;
-          case LowLevelCAS.TYPE_CLASS_LONGARRAY:
-            fs = new LongArrayFSImpl(addr, cds.cas);
-            break;
-          case LowLevelCAS.TYPE_CLASS_DOUBLEARRAY:
-            fs = new DoubleArrayFSImpl(addr, cds.cas);
-            break;
-          case LowLevelCAS.TYPE_CLASS_BYTEARRAY:
-            fs = new ByteArrayFSImpl(addr, cds.cas);
-            break;
-          default: {
-            return "";
-          }
-        }
+        // is not FSarray, is not ByteArray, is not String Array
+//        CommonArrayFS fs;
+//        String[] fsvalues;
+//
+//        switch (arrayType) {
+//          case LowLevelCAS.TYPE_CLASS_INTARRAY:
+//            fs = new IntArrayFSImpl(addr, cds.cas);
+//            break;
+//          case LowLevelCAS.TYPE_CLASS_FLOATARRAY:
+//            fs = new FloatArrayFSImpl(addr, cds.cas);
+//            break;
+//          case LowLevelCAS.TYPE_CLASS_BOOLEANARRAY:
+//            fs = new BooleanArrayFSImpl(addr, cds.cas);
+//            break;
+//          case LowLevelCAS.TYPE_CLASS_SHORTARRAY:
+//            fs = new ShortArrayFSImpl(addr, cds.cas);
+//            break;
+//          case LowLevelCAS.TYPE_CLASS_LONGARRAY:
+//            fs = new LongArrayFSImpl(addr, cds.cas);
+//            break;
+//          case LowLevelCAS.TYPE_CLASS_DOUBLEARRAY:
+//            fs = new DoubleArrayFSImpl(addr, cds.cas);
+//            break;
+//          case LowLevelCAS.TYPE_CLASS_BYTEARRAY:
+//            fs = new ByteArrayFSImpl(addr, cds.cas);
+//            break;
+//          default: {
+//            return "";
+//          }
+//        }
 
 //        if (arrayType == LowLevelCAS.TYPE_CLASS_STRINGARRAY) {   // this method never called for StringArrays
 //          StringArrayFS strFS = new StringArrayFSImpl(addr, cds.cas);
 //          fsvalues = strFS.toArray();
 //        } else {
-        fsvalues = fs.toStringArray();
+        String[] fsvalues = fs.toStringArray();
 //        }
 
         for (String s : fsvalues) {
@@ -1114,24 +1127,17 @@ public class XmiCasSerializer {
     
     private void stringArrayToElementList(
         String featName, 
-        int addr, 
+        StringArray stringArray, 
         List<? super XmlElementNameAndContents> resultList) {
-      if (addr == CASImpl.NULL) {
+      if (stringArray == null) {
         return;
       }
-
       // it is not safe to use a space-separated attribute, which would
       // break for strings containing spaces. So use child elements instead.
-      final int size = cds.cas.ll_getArraySize(addr);
-    //  if (size > 0 && !arrayAndListFSs.put(addr, addr)) {
-    //    reportWarning("Warning: multiple references to a String array.  Reference identity will not be preserved.");
-    //  }
-      int pos = cds.cas.getArrayStartAddress(addr);
-      for (int j = 0; j < size; j++) {
-        String s = cds.cas.getStringForCode(cds.cas.getHeapValue(pos));
+      
+      for (String s : stringArray._getTheArray()) {
         resultList.add(new XmlElementNameAndContents(new XmlElementName(null, featName, featName),
-                s));
-        ++pos;
+            s));
       }
     }
 
@@ -1147,20 +1153,16 @@ public class XmiCasSerializer {
      * @return String representation of the array, or null if passed in CASImpl.NULL
      * @throws SAXException passthru
      */
-    private String listToString(int curNode) throws SAXException {
-      if (curNode == CASImpl.NULL) {
+    private String listToString(CommonList fs) throws SAXException {
+      if (fs == null) {
         return null;  // different from ""
       }
       final StringBuilder sb = new StringBuilder();
-      cds.listUtils.anyListToOutput(curNode, cds.sharedData, cds, new ListUtils.ListOutput() {
-       @Override
-        void append(String item) {
-          if (sb.length() > 0) {
-            sb.append(' ');
-          }
-          sb.append(item);
-        }
-      });    
+      fs.anyListToOutput(cds.sharedData, cds, s -> {if (sb.length() > 0) {
+                                                     sb.append(' ').append(s);
+                                                    } else {
+                                                     sb.append(s);
+                                                    }});
       return sb.toString();
     }
 
@@ -1232,9 +1234,9 @@ public class XmiCasSerializer {
     protected void addNameSpace(XmlElementName xmlElementName) {};
 
     @Override
-    protected boolean writeFsStart(int addr, int typeCode /* ignored */) {
+    protected boolean writeFsStart(TOP fs, int typeCode /* ignored */) {
       workAttrs.clear();
-      addAttribute(workAttrs, ID_ATTR_NAME, cds.getXmiId(addr));
+      addAttribute(workAttrs, ID_ATTR_NAME, cds.getXmiId(fs));
       return false;  // ignored
     }
    
@@ -1288,7 +1290,7 @@ public class XmiCasSerializer {
     protected void writeEndOfIndividualFs() {}
 
     @Override
-    protected void writeFsRef(int addr) throws Exception {} // only for JSON, not used here
+    protected void writeFsRef(TOP fs) throws Exception {} // only for JSON, not used here
      
   }
         
@@ -1297,5 +1299,4 @@ public class XmiCasSerializer {
 //    return new XmiDocSerializer(ch, cas, null);
 //  }  
   
-
 }

Modified: uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiSerializationSharedData.java
URL: http://svn.apache.org/viewvc/uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiSerializationSharedData.java?rev=1715964&r1=1715963&r2=1715964&view=diff
==============================================================================
--- uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiSerializationSharedData.java (original)
+++ uima/uimaj/branches/experiment-v3-jcas/uimaj-core/src/main/java/org/apache/uima/cas/impl/XmiSerializationSharedData.java Mon Nov 23 21:32:16 2015
@@ -20,18 +20,22 @@
 package org.apache.uima.cas.impl;
 
 import java.util.ArrayList;
-import java.util.BitSet;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.uima.internal.util.Int2IntHashMap;
-import org.apache.uima.internal.util.IntListIterator;
+import org.apache.uima.internal.util.Int2ObjHashMap;
+import org.apache.uima.internal.util.Obj2IntIdentityHashMap;
 import org.apache.uima.internal.util.XmlAttribute;
 import org.apache.uima.internal.util.XmlElementName;
 import org.apache.uima.internal.util.XmlElementNameAndContents;
+import org.apache.uima.jcas.cas.FSArray;
+import org.apache.uima.jcas.cas.TOP;
+import org.xml.sax.Attributes;
 
 /**
  * A container for data that is shared between the {@link XmiCasSerializer} and the {@link XmiCasDeserializer}.
@@ -51,25 +55,33 @@ import org.apache.uima.internal.util.Xml
  *   <li>After calling the XmiCasSerializer and passing an <code>XmiSerializationSharedData</code>, you can call the
  *       {@link #getMaxXmiId()} method to get the maximum xmi:id value in the serialized CAS.  This feature, along with the consistency of
  *       xmi:id values, allows merging multiple XMI documents into a single CAS.  See TODO.</li>
- * </ul>       
+ * </ul>  
+ * 
+ * <p>Inner classes are used to hold information about Feature Structure elements, both for out-of-typesystem data, and also
+ * when deserializing pre V3 xmi serializations where the Sofa FS are not guaranteed to come before other Feature Structures that
+ * depend on them.</p>
  * 
  */
 public class XmiSerializationSharedData {
   /**
+   * V3: FSs have an id - use that.  (Assumes id's are internal ones)
+   * 
    * A map from FeatureStructure address to xmi:id. This is populated whenever
    * an XMI element is serialized or deserialized.  It is used by the
    * getXmiId() method, which is done to ensure a consistent ID for each FS 
    * address across multiple serializations.
    */
-  private Int2IntHashMap fsAddrToXmiIdMap = new Int2IntHashMap();
+  private Obj2IntIdentityHashMap<TOP> fsToXmiId = new Obj2IntIdentityHashMap<>(TOP.class, TOP.singleton);
   
-  /** 
+  /**
+   * V3: use the cas's getFsFromId   (Assumes id's are internal ones)
+   *  
    * A map from xmi:id to FeatureStructure address.  This is populated whenever
    * an XMI element is serialized or deserialized.  It is used by the
    * getFsAddrForXmiId() method, necessary to support merging multiple XMI
    * CASes into the same CAS object.
    **/
-  private Int2IntHashMap xmiIdToFsAddrMap = new Int2IntHashMap();
+  private Int2ObjHashMap<TOP> xmiIdToFs = new Int2ObjHashMap<>(TOP.class);
   
   /**
    * List of OotsElementData objects, each of which captures information about
@@ -78,23 +90,25 @@ public class XmiSerializationSharedData
   private List<OotsElementData> ootsFs = new ArrayList<OotsElementData>();
   
   /**
-   * Map that from the xmi:id (String) of a Sofa to a List of xmi:id's (Strings) for
+   * Map from the xmi:id (String) of a Sofa to a List of xmi:id's (Strings) for
    * the out-of-typesystem FSs that are members of that Sofa's view.
    */
   private Map<String, List<String>> ootsViewMembers = new HashMap<String, List<String>>();
 
-  /** Map from Feature Structure address (Integer) to OotsElementData object, capturing information 
+  /** Map from Feature Structures to OotsElementData object, capturing information 
    * about out-of-typesystem features that were part of an in-typesystem FS.  These include both
    * features not defined in the typesystem and features that are references to out-of-typesystem
    * elements.  This information needs to be included when the FS is subsequently serialized.
    */
-  private Map<Integer, OotsElementData> ootsFeatures = new HashMap<Integer, OotsElementData>();
+  private Map<TOP, OotsElementData> ootsFeatures = new IdentityHashMap<>();
   
-  /** Map from Feature Structure address (Integer) of an FSArray to a list of 
+  /** 
+   * V3: Key is FSArray
+   * Map from an FSArray to a list of 
    * {@link XmiArrayElement} objects, each of which holds an index and an xmi:id
    * for an out-of-typesystem array element.
    */
-  private Map<Integer, List<XmiArrayElement>> ootsArrayElements = new HashMap<Integer, List<XmiArrayElement>>();
+  private Map<FSArray, List<XmiArrayElement>> ootsArrayElements = new HashMap<>();
   
   /**
    * The maximum XMI ID used in the serialization. Used to generate unique IDs if needed.
@@ -103,31 +117,46 @@ public class XmiSerializationSharedData
   
   
   /**
+   * V3: key is TOP, value is TOP
+   * 
    * Map from FS address of a non-shared multi-valued (Array/List) FS to the 
    * FS address of the encompassing FS which has a feature whose value is this multi-valued FS.
    * Used when deserializing a Delta CAS to find and serialize the encompassing FS when 
    * the non-shared array/list FS is modified. 
    */
-  Int2IntHashMap nonsharedfeatureIdToFSId = new Int2IntHashMap();
+  Map<TOP, TOP> nonsharedfeatureIdToFSId = new IdentityHashMap<>();
+//  Int2IntHashMap nonsharedfeatureIdToFSId = new Int2IntHashMap();
 
-  void addIdMapping(int fsAddr, int xmiId) {
-    fsAddrToXmiIdMap.put(fsAddr, xmiId);
-    xmiIdToFsAddrMap.put(xmiId, fsAddr);
+  void addIdMapping(TOP fs, int xmiId) {
+    fsToXmiId.put(fs, xmiId);
+    xmiIdToFs.put(xmiId, fs);
     if (xmiId > maxXmiId)
       maxXmiId = xmiId;
   }
 
-  String getXmiId(int fsAddr) {
-    return Integer.toString(getXmiIdAsInt(fsAddr));
+  public String getXmiId(TOP fs) {
+    return Integer.toString(getXmiIdAsInt(fs));
   }
 
-  int getXmiIdAsInt(int fsAddr) {
+  /**
+   * Gets the FS address that corresponds to the given xmi:id, in the most
+   * recent serialization or deserialization.
+   *   
+   * @param xmiId an xmi:id from the most recent XMI CAS that was serialized
+   *   or deserialized.
+   * @return the FeatureStructure corresponding to that xmi:id, null if none.
+   */
+  public TOP getFsForXmiId(int xmiId) {
+    return (TOP) xmiIdToFs.get(xmiId);
+  }
+
+  int getXmiIdAsInt(TOP fs) {
     // see if we already have a mapping
-    int xmiId = fsAddrToXmiIdMap.get(fsAddr);
+    int xmiId = fsToXmiId.get(fs);
     if (xmiId == 0) {
       // to be sure we get a unique Id, increment maxXmiId and use that
       xmiId = ++maxXmiId;
-      addIdMapping(fsAddr, xmiId);
+      addIdMapping(fs, xmiId);
     }
     return xmiId;
   }
@@ -140,19 +169,19 @@ public class XmiSerializationSharedData
     return maxXmiId;
   }
   
-  /**
-   * Gets the FS address that corresponds to the given xmi:id, in the most
-   * recent serialization or deserialization.
-   *   
-   * @param xmiId an xmi:id from the most recent XMI CAS that was serialized
-   *   or deserialized.
-   * @return the FS address of the FeatureStructure corresponding to that
-   *   xmi:id, -1 if none.
-   */
-  public int getFsAddrForXmiId(int xmiId) {
-    final int addr = xmiIdToFsAddrMap.get(xmiId);
-    return addr == 0 ? -1 : addr;
-  }
+//  /**
+//   * Gets the FS address that corresponds to the given xmi:id, in the most
+//   * recent serialization or deserialization.
+//   *   
+//   * @param xmiId an xmi:id from the most recent XMI CAS that was serialized
+//   *   or deserialized.
+//   * @return the FS address of the FeatureStructure corresponding to that
+//   *   xmi:id, -1 if none.
+//   */
+//  public int getFsAddrForXmiId(int xmiId) {
+//    final int addr = xmiIdToFs.get(xmiId);
+//    return addr == 0 ? -1 : addr;
+//  }
   
   /** 
    * Clears the ID mapping information that was populated in
@@ -160,8 +189,8 @@ public class XmiSerializationSharedData
    * TODO: maybe a more general reset that resets other things?
    */
   public void clearIdMap() {
-    fsAddrToXmiIdMap.clear();
-    xmiIdToFsAddrMap.clear();
+    fsToXmiId.clear();
+    xmiIdToFs.clear();
     nonsharedfeatureIdToFSId.clear();
     maxXmiId = 0;
   }
@@ -221,12 +250,11 @@ public class XmiSerializationSharedData
    * @param featName name of the feature
    * @param featVal value of the feature, as a string
    */
-  public void addOutOfTypeSystemAttribute(int addr, String featName, String featVal) {
-    Integer key = Integer.valueOf(addr);
-    OotsElementData oed = this.ootsFeatures.get(key);
+  public void addOutOfTypeSystemAttribute(TOP fs, String featName, String featVal) {
+    OotsElementData oed = this.ootsFeatures.get(fs);
     if (oed == null) {
-      oed = new OotsElementData();
-      this.ootsFeatures.put(key, oed);
+      oed = new OotsElementData(null, null, -1, -1);
+      this.ootsFeatures.put(fs, oed);
     }
     oed.attributes.add(new XmlAttribute(featName, featVal));
   }  
@@ -238,12 +266,11 @@ public class XmiSerializationSharedData
    * @param featName name of the feature (element tag name)
    * @param featVals values of the feature, as a List of strings
    */
-  public void addOutOfTypeSystemChildElements(int addr, String featName, List<String> featVals) {
-    Integer key = Integer.valueOf(addr);
-    OotsElementData oed = this.ootsFeatures.get(key);
+  public void addOutOfTypeSystemChildElements(TOP fs, String featName, List<String> featVals) {
+    OotsElementData oed = this.ootsFeatures.get(fs);
     if (oed == null) {
-      oed = new OotsElementData();
-      this.ootsFeatures.put(key, oed);
+      oed = new OotsElementData(null, null, -1, -1);
+      this.ootsFeatures.put(fs, oed);
     }
     Iterator<String> iter = featVals.iterator();
     XmlElementName elemName = new XmlElementName(null,featName,featName);
@@ -259,17 +286,18 @@ public class XmiSerializationSharedData
    * @return object containing information about out-of-typesystem features
    *   (both attributes and child elements)
    */
-  public OotsElementData getOutOfTypeSystemFeatures(int addr) {
-    Integer key = Integer.valueOf(addr);
-    return this.ootsFeatures.get(key);
+  public OotsElementData getOutOfTypeSystemFeatures(TOP fs) {
+    return this.ootsFeatures.get(fs);
   }
   
   /**
    * Get all FS Addresses that have been added to the id map.
    * @return an array containing all the FS addresses
    */
-  public int[] getAllFsAddressesInIdMap() {
-    return fsAddrToXmiIdMap.getSortedKeys();
+  public TOP[] getAndSortByIdAllFSsInIdMap() {
+    TOP[] keys= fsToXmiId.getKeys();
+    Arrays.sort(keys, (fs1, fs2) -> Integer.compare(fs1._id, fs2._id));
+    return keys;
   }  
   
   /**
@@ -279,8 +307,8 @@ public class XmiSerializationSharedData
    *   holds the index and xmi:id of an array element that is a
    *   reference to an out-of-typesystem FS.
    */
-  public List<XmiArrayElement> getOutOfTypeSystemArrayElements(int addr) {
-    return this.ootsArrayElements.get(Integer.valueOf(addr));
+  public List<XmiArrayElement> getOutOfTypeSystemArrayElements(FSArray fsarray) {
+    return this.ootsArrayElements.get(fsarray);
   }
   
   public boolean hasOutOfTypeSystemArrayElements() {
@@ -294,12 +322,11 @@ public class XmiSerializationSharedData
    * @param index index into array 
    * @param xmiId xmi:id of the out-of-typesystem element that is the value at the given index
    */
-  public void addOutOfTypeSystemArrayElement(int addr, int index, int xmiId) {
-    Integer key = Integer.valueOf(addr);
-    List<XmiArrayElement> list = this.ootsArrayElements.get(key);
+  public void addOutOfTypeSystemArrayElement(FSArray fsarray, int index, int xmiId) {
+    List<XmiArrayElement> list = this.ootsArrayElements.get(fsarray);
     if (list == null) {
       list = new ArrayList<XmiArrayElement>();
-      this.ootsArrayElements.put(key, list);
+      this.ootsArrayElements.put(fsarray, list);
     }
     list.add(new XmiArrayElement(index, Integer.toString(xmiId)));
   }
@@ -311,82 +338,165 @@ public class XmiSerializationSharedData
    * @param nonsharedFSAddr - fs address of non-shared multi-valued feature value
    * @param fsAddr - fs address of encompassing featurestructure
    */
-  public void addNonsharedRefToFSMapping(int nonsharedFSAddr, int fsAddr) {
-	this.nonsharedfeatureIdToFSId.put(nonsharedFSAddr, fsAddr);
+  public void addNonsharedRefToFSMapping(TOP nonsharedFS, TOP fs) {
+	this.nonsharedfeatureIdToFSId.put(nonsharedFS, fs);
   }
   
   /**
    * 
    * @return the non-shared featureId to FS Id key set
    */
-  public int[] getNonsharedMulitValuedFSs() {
-    return this.nonsharedfeatureIdToFSId.getSortedKeys();
+  public TOP[] getNonsharedMulitValuedFSs() {
+    return getSortedKeys(this.nonsharedfeatureIdToFSId);
+  }
+  
+  private TOP[] getSortedKeys(Map<TOP, ?> map) {
+    TOP[] keys = map.keySet().toArray(new TOP[map.size()]);
+    Arrays.sort(keys, (fs1, fs2) -> Integer.compare(fs1._id, fs2._id));
+    return keys;
   }
   
   /**
    * 
-   * @param nonsharedFS an id of a nonsharedFS
-   * @return the int handle to the encompassing FS or -1 if not found
+   * @param nonsharedFS a nonsharedFS
+   * @return the encompassing FS or null if not found
    */
-  public int getEncompassingFS(int nonsharedFS) {
-	int addr = nonsharedfeatureIdToFSId.get(nonsharedFS);
-	return addr == 0 ? -1 : addr;
+  public TOP getEncompassingFS(TOP nonsharedFS) {
+	return  nonsharedfeatureIdToFSId.get(nonsharedFS);
   }
   
   /**
    * For debugging purposes only.
    */
-  void checkForDups() {
-    BitSet ids = new BitSet();
-    IntListIterator iter = fsAddrToXmiIdMap.keyIterator();
-    while (iter.hasNext()) {
-      int xmiId = iter.next();
-      if (ids.get(xmiId)) {
-        throw new RuntimeException("Duplicate ID " + xmiId + "!");
-      }
-      ids.set(xmiId);
-    }
-  }
+//  void checkForDups() {
+//    BitSet ids = new BitSet();
+//    IntListIterator iter = fsToXmiId.keyIterator();
+//    while (iter.hasNext()) {
+//      int xmiId = iter.next();
+//      if (ids.get(xmiId)) {
+//        throw new RuntimeException("Duplicate ID " + xmiId + "!");
+//      }
+//      ids.set(xmiId);
+//    }
+//  }
 
   /**
    * For debugging purposes only.
    */
   public String toString() {
-    StringBuffer buf = new StringBuffer();
-    int[] keys = fsAddrToXmiIdMap.getSortedKeys();
-    for (int i = 0; i < keys.length; i++) {
-      buf.append(keys[i]).append(": ").append(fsAddrToXmiIdMap.get(keys[i])).append('\n');
+    StringBuilder buf = new StringBuilder();
+    TOP[] keys = getAndSortByIdAllFSsInIdMap();
+    for (TOP fs : keys) {
+      buf.append(fs.id()).append(": ").append(fsToXmiId.get(fs)).append('\n');
     }
     return buf.toString();
   }
 
   /**
-   * Data structure holding all information about an XMI element
-   * containing an out-of-typesystem FS.
+   * <p>Data structure holding all information about an XMI element
+   * containing an out-of-typesystem FS.</p>
+   * 
+   * <p>Also used to hold information for deferring deserialization of subtypes of AnnotationBase when the sofa
+   * is not yet known</p>
+   * 
    */
-  static class OotsElementData {
+  public static class OotsElementData {
     /**
      * xmi:id of the element
      */
-    String xmiId;
+    final String xmiId;
 
     /**
      * Name of the element, including XML namespace.
      */
-    XmlElementName elementName;
+    final XmlElementName elementName;
 
     /**
      * List of XmlAttribute objects each holding name and value of an attribute.
      */
-    List<XmlAttribute> attributes = new ArrayList<XmlAttribute>();
+    final public List<XmlAttribute> attributes = new ArrayList<XmlAttribute>();
     
     /**
      * List of XmlElementNameAndContents objects each describing one of the
      * child elements representing features of this out-of-typesystem element.
      */
-    List<XmlElementNameAndContents> childElements = new ArrayList<XmlElementNameAndContents>();
+    final List<XmlElementNameAndContents> childElements = new ArrayList<XmlElementNameAndContents>();
+    
+    final int lineNumber;
+    
+    final int colNumber;
+    
+    public OotsElementData(String xmiId, XmlElementName elementName) {
+      this(xmiId, elementName, -1, -1);
+    }
+    
+    public OotsElementData(String xmiId, XmlElementName elementName, int lineNumber, int colNumber) {
+      this.xmiId = xmiId;
+      this.elementName = elementName;
+      this.lineNumber = lineNumber;
+      this.colNumber = colNumber;
+    }
+    
+    public Attributes getAttributes() {
+      return new Attributes() {
+
+        @Override
+        public int getLength() { return attributes.size(); }
+
+        @Override
+        public String getURI(int index) { throw new UnsupportedOperationException(); }
+
+        @Override
+        public String getLocalName(int index) { throw new UnsupportedOperationException(); }
+
+        @Override
+        public String getQName(int index) { return attributes.get(index).name; }
+
+
+        @Override
+        public String getType(int index) { throw new UnsupportedOperationException(); }
+ 
+        @Override
+        public String getValue(int index) { return attributes.get(index).value; }
+
+        @Override
+        public int getIndex(String uri, String localName) { throw new UnsupportedOperationException(); } 
+
+        @Override
+        public int getIndex(String qName) {
+          int i = 0;
+          for (XmlAttribute attr : attributes) {
+            if (attr.name.equals(qName)) {
+              return i;
+            }
+            i++;
+          }
+          return -1;
+        }
+
+        @Override
+        public String getType(String uri, String localName) { throw new UnsupportedOperationException(); } 
+
+        @Override
+        public String getType(String qName) { throw new UnsupportedOperationException(); }
+
+        @Override
+        public String getValue(String uri, String localName) { throw new UnsupportedOperationException(); }
+
+        @Override
+        public String getValue(String qName) {
+          for (XmlAttribute attr : attributes) {
+            if (attr.name.equals(qName)) {
+              return attr.value;
+            }
+          }
+          return null;
+        }
+      };
+    }
   }
   
+  
   /** 
    * Data structure holding the index and the xmi:id of an array or list element that
    * is a reference to an out-of-typesystem FS.