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.
