| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.uima.cas.impl; |
| |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.ListIterator; |
| |
| import org.apache.uima.cas.CAS; |
| import org.apache.uima.cas.impl.XmiSerializationSharedData.OotsElementData; |
| import org.apache.uima.internal.util.IntVector; |
| import org.apache.uima.internal.util.XmlAttribute; |
| import org.apache.uima.internal.util.rb_trees.IntRedBlackTree; |
| import org.apache.uima.util.Level; |
| import org.apache.uima.util.Logger; |
| import org.xml.sax.ErrorHandler; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| |
| /** |
| * Utilities for dealing with CAS List types. |
| * |
| */ |
| public class ListUtils { |
| CASImpl cas; |
| |
| // list type and feature codes |
| private int intListType; |
| |
| private int floatListType; |
| |
| private int stringListType; |
| |
| private int fsListType; |
| |
| private int neIntListType; |
| |
| private int neFloatListType; |
| |
| private int neStringListType; |
| |
| private int neFsListType; |
| |
| private int eIntListType; |
| |
| private int eFloatListType; |
| |
| private int eStringListType; |
| |
| private int eFsListType; |
| |
| private int intHeadFeat; |
| |
| private int intTailFeat; |
| |
| private int floatHeadFeat; |
| |
| private int floatTailFeat; |
| |
| private int stringHeadFeat; |
| |
| private int stringTailFeat; |
| |
| private int fsHeadFeat; |
| |
| private int fsTailFeat; |
| |
| private Logger logger; |
| |
| private ErrorHandler eh; |
| |
| /** |
| * Creates a new ListUtils object. |
| * |
| * @param aCASImpl |
| * the CAS that this ListUtils will operate on |
| * @param aLogger |
| * optional logger, to receive warning messages |
| * @param aErrorHandler |
| * optional SAX ErrorHandler, to receive warning messages |
| */ |
| public ListUtils(CASImpl aCASImpl, Logger aLogger, ErrorHandler aErrorHandler) { |
| this.cas = aCASImpl; |
| this.logger = aLogger; |
| this.eh = aErrorHandler; |
| TypeSystemImpl ts = aCASImpl.getTypeSystemImpl(); |
| this.intListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_INTEGER_LIST); |
| this.floatListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_FLOAT_LIST); |
| this.stringListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_STRING_LIST); |
| this.fsListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_FS_LIST); |
| this.neIntListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_NON_EMPTY_INTEGER_LIST); |
| this.neFloatListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_NON_EMPTY_FLOAT_LIST); |
| this.neStringListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_NON_EMPTY_STRING_LIST); |
| this.neFsListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_NON_EMPTY_FS_LIST); |
| this.eIntListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_EMPTY_INTEGER_LIST); |
| this.eFloatListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_EMPTY_FLOAT_LIST); |
| this.eStringListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_EMPTY_STRING_LIST); |
| this.eFsListType = ts.ll_getCodeForTypeName(CAS.TYPE_NAME_EMPTY_FS_LIST); |
| this.intHeadFeat = ts.ll_getCodeForFeatureName(CAS.FEATURE_FULL_NAME_INTEGER_LIST_HEAD); |
| this.floatHeadFeat = ts.ll_getCodeForFeatureName(CAS.FEATURE_FULL_NAME_FLOAT_LIST_HEAD); |
| this.stringHeadFeat = ts.ll_getCodeForFeatureName(CAS.FEATURE_FULL_NAME_STRING_LIST_HEAD); |
| this.fsHeadFeat = ts.ll_getCodeForFeatureName(CAS.FEATURE_FULL_NAME_FS_LIST_HEAD); |
| this.intTailFeat = ts.ll_getCodeForFeatureName(CAS.FEATURE_FULL_NAME_INTEGER_LIST_TAIL); |
| this.floatTailFeat = ts.ll_getCodeForFeatureName(CAS.FEATURE_FULL_NAME_FLOAT_LIST_TAIL); |
| this.stringTailFeat = ts.ll_getCodeForFeatureName(CAS.FEATURE_FULL_NAME_STRING_LIST_TAIL); |
| this.fsTailFeat = ts.ll_getCodeForFeatureName(CAS.FEATURE_FULL_NAME_FS_LIST_TAIL); |
| } |
| |
| public boolean isIntListType(int type) { |
| return (type == this.intListType || type == this.neIntListType || type == this.eIntListType); |
| } |
| |
| public boolean isFloatListType(int type) { |
| return (type == this.floatListType || type == this.neFloatListType || type == this.eFloatListType); |
| } |
| |
| public boolean isStringListType(int type) { |
| return (type == this.stringListType || type == this.neStringListType || type == this.eStringListType); |
| } |
| |
| public boolean isFsListType(int type) { |
| return (type == this.fsListType || type == this.neFsListType || type == this.eFsListType); |
| } |
| |
| public boolean isListType(int type) { |
| return isIntListType(type) || isFloatListType(type) || isStringListType(type) |
| || isFsListType(type); |
| } |
| |
| public int getLength(int type, int addr) { |
| int neListType = -1; |
| int tailFeat = -1; |
| if (isIntListType(type)) { |
| neListType = neIntListType; |
| tailFeat = intTailFeat; |
| } else if ( isFloatListType(type)) { |
| neListType = neFloatListType; |
| tailFeat = floatTailFeat; |
| } else if (isStringListType(type)) { |
| neListType = neStringListType; |
| tailFeat = stringTailFeat; |
| } else if (isFsListType(type)) { |
| neListType = neFsListType; |
| tailFeat = fsTailFeat; |
| } |
| IntRedBlackTree visited = new IntRedBlackTree(); |
| boolean foundCycle = false; |
| // first count length of list so we can allocate array |
| int length = 0; |
| int curNode = addr; |
| while (cas.getHeapValue(curNode) == neListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| length++; |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(tailFeat)); |
| } |
| return length; |
| } |
| |
| public String[] intListToStringArray(int addr) throws SAXException { |
| IntRedBlackTree visited = new IntRedBlackTree(); |
| boolean foundCycle = false; |
| // first count length of list so we can allocate array |
| int length = 0; |
| int curNode = addr; |
| while (cas.getHeapValue(curNode) == neIntListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| length++; |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(intTailFeat)); |
| } |
| |
| String[] array = new String[length]; |
| |
| // now populate list |
| curNode = addr; |
| for (int i = 0; i < length; i++) { |
| array[i] = Integer.toString(cas.getHeapValue(curNode + cas.getFeatureOffset(intHeadFeat))); |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(intTailFeat)); |
| } |
| if (foundCycle) { |
| reportWarning("Found a cycle in an IntegerList. List truncated to " |
| + Arrays.asList(array).toString()); |
| } |
| return array; |
| } |
| |
| public String[] floatListToStringArray(int addr) throws SAXException { |
| boolean foundCycle = false; |
| IntRedBlackTree visited = new IntRedBlackTree(); |
| // first count length of list so we can allocate array |
| int length = 0; |
| int curNode = addr; |
| while (cas.getHeapValue(curNode) == neFloatListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| length++; |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(floatTailFeat)); |
| } |
| |
| String[] array = new String[length]; |
| |
| // now populate list |
| curNode = addr; |
| for (int i = 0; i < length; i++) { |
| array[i] = Float.toString(CASImpl.int2float(cas.getHeapValue(curNode |
| + cas.getFeatureOffset(floatHeadFeat)))); |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(floatTailFeat)); |
| } |
| if (foundCycle) { |
| reportWarning("Found a cycle in a FloatList. List truncated to " |
| + Arrays.asList(array).toString() + "."); |
| } |
| return array; |
| } |
| |
| public String[] stringListToStringArray(int addr) throws SAXException { |
| boolean foundCycle = false; |
| IntRedBlackTree visited = new IntRedBlackTree(); |
| // first count length of list so we can allocate array |
| int length = 0; |
| int curNode = addr; |
| while (cas.getHeapValue(curNode) == neStringListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| length++; |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(stringTailFeat)); |
| } |
| |
| String[] array = new String[length]; |
| |
| // now populate list |
| curNode = addr; |
| for (int i = 0; i < length; i++) { |
| array[i] = cas.getStringForCode(cas.getHeapValue(curNode |
| + cas.getFeatureOffset(stringHeadFeat))); |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(stringTailFeat)); |
| } |
| if (foundCycle) { |
| reportWarning("Found a cycle in a StringList. List truncated to " |
| + Arrays.asList(array).toString() + "."); |
| } |
| return array; |
| } |
| |
| public String[] fsListToXmiIdStringArray(int addr, XmiSerializationSharedData sharedData) |
| throws SAXException { |
| boolean foundCycle = false; |
| IntRedBlackTree visited = new IntRedBlackTree(); |
| // first count length of list so we can allocate array |
| int length = 0; |
| int curNode = addr; |
| while (cas.getHeapValue(curNode) == neFsListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| length++; |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(fsTailFeat)); |
| } |
| |
| String[] strArray = new String[length]; |
| |
| // now populate list |
| curNode = addr; |
| for (int i = 0; i < length; i++) { |
| int heapVal = cas.getHeapValue(curNode + cas.getFeatureOffset(fsHeadFeat)); |
| if (heapVal == 0) { |
| //null value in list. Represent with "0". |
| strArray[i] = "0"; |
| // However, this may be null because the element was originally a reference to an |
| // out-of-typesystem FS, so chck the XmiSerializationSharedData |
| if (sharedData != null) { |
| OotsElementData oed = sharedData.getOutOfTypeSystemFeatures(curNode); |
| if (oed != null) { |
| assert oed.attributes.size() == 1; //only the head feature can possibly be here |
| XmlAttribute attr = (XmlAttribute)oed.attributes.get(0); |
| assert CAS.FEATURE_BASE_NAME_HEAD.equals(attr.name); |
| strArray[i] = attr.value; |
| } |
| } |
| } |
| else { |
| if (sharedData != null) { |
| strArray[i] = heapVal == 0 ? null : sharedData.getXmiId(heapVal); |
| } else { |
| strArray[i] = Integer.toString(heapVal); |
| } |
| } |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(fsTailFeat)); |
| } |
| if (foundCycle) { |
| reportWarning("Found a cycle in an FSList. List truncated to " |
| + Arrays.asList(strArray).toString() + "."); |
| } |
| return strArray; |
| } |
| |
| public int[] fsListToAddressArray(int addr) throws SAXException { |
| boolean foundCycle = false; |
| IntRedBlackTree visited = new IntRedBlackTree(); |
| // first count length of list so we can allocate array |
| int length = 0; |
| int curNode = addr; |
| while (cas.getHeapValue(curNode) == neFsListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| length++; |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(fsTailFeat)); |
| } |
| |
| int[] array = new int[length]; |
| |
| // now populate list |
| curNode = addr; |
| for (int i = 0; i < length; i++) { |
| array[i] = cas.getHeapValue(curNode + cas.getFeatureOffset(fsHeadFeat)); |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(fsTailFeat)); |
| } |
| if (foundCycle) { |
| reportWarning("Found a cycle in an FSList. List truncated where cycle occurs."); |
| } |
| return array; |
| } |
| |
| public int createIntList(List<String> stringValues) { |
| int first = cas.ll_createFS(eIntListType); |
| ListIterator<String> iter = stringValues.listIterator(stringValues.size()); |
| while (iter.hasPrevious()) { |
| int value = Integer.parseInt((String) iter.previous()); |
| int node = cas.ll_createFS(neIntListType); |
| cas.setFeatureValue(node, intHeadFeat, value); |
| cas.setFeatureValue(node, intTailFeat, first); |
| first = node; |
| } |
| return first; |
| } |
| |
| public int createFloatList(List<String> stringValues) { |
| int first = cas.ll_createFS(eFloatListType); |
| ListIterator<String> iter = stringValues.listIterator(stringValues.size()); |
| while (iter.hasPrevious()) { |
| float value = Float.parseFloat((String) iter.previous()); |
| int node = cas.ll_createFS(neFloatListType); |
| cas.setFeatureValue(node, floatHeadFeat, CASImpl.float2int(value)); |
| cas.setFeatureValue(node, floatTailFeat, first); |
| first = node; |
| } |
| return first; |
| } |
| |
| public int createStringList(List<String> stringValues) { |
| int first = cas.ll_createFS(eStringListType); |
| ListIterator<String> iter = stringValues.listIterator(stringValues.size()); |
| while (iter.hasPrevious()) { |
| String value = iter.previous(); |
| int node = cas.ll_createFS(neStringListType); |
| cas.setFeatureValue(node, stringHeadFeat, cas.addString(value)); |
| cas.setFeatureValue(node, stringTailFeat, first); |
| first = node; |
| } |
| return first; |
| } |
| |
| public int createFsList(List<String> stringValues, IntVector fsAddresses) { |
| int first = cas.ll_createFS(eFsListType); |
| ListIterator<String> iter = stringValues.listIterator(stringValues.size()); |
| while (iter.hasPrevious()) { |
| int value = Integer.parseInt((String) iter.previous()); |
| int node = cas.ll_createFS(neFsListType); |
| fsAddresses.add(node); |
| cas.setFeatureValue(node, fsHeadFeat, value); |
| cas.setFeatureValue(node, fsTailFeat, first); |
| first = node; |
| } |
| return first; |
| } |
| |
| public int updateIntList(int addr, List<String> stringValues) throws SAXException { |
| int first = addr; |
| int currLength = this.getLength(this.neIntListType, addr); |
| int curNode = addr; |
| int prevNode = 0; |
| IntRedBlackTree visited = new IntRedBlackTree(); |
| boolean foundCycle = false; |
| int i =0; |
| |
| //if (currLength != stringValues.size() ) { |
| // first = createIntList(stringValues); |
| |
| if (currLength < stringValues.size()) { |
| while (cas.getHeapValue(curNode) == neIntListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| int value = Integer.parseInt(stringValues.get(i++)); |
| cas.setFeatureValue(curNode,floatHeadFeat, value); |
| prevNode = curNode; |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(intTailFeat)); |
| } |
| //add nodes for remaining values |
| if (i < stringValues.size()) { |
| int emptyListFs = curNode; |
| //check that first is eintlisttype |
| while (i < stringValues.size()) { |
| int newNode = cas.ll_createFS(neIntListType); |
| int value = Integer.parseInt((String) stringValues.get(i++)); |
| cas.setFeatureValue(newNode,intHeadFeat, value); |
| cas.setFeatureValue(newNode, intTailFeat, emptyListFs); |
| cas.setFeatureValue(prevNode, intTailFeat, newNode); |
| prevNode = newNode; |
| } |
| } |
| } else if (currLength > stringValues.size()) { |
| while (cas.getHeapValue(curNode) == neIntListType && i < stringValues.size()) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| float value = Integer.parseInt((String) stringValues.get(i++)); |
| cas.setFeatureValue(curNode,intHeadFeat, value); |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(intTailFeat)); |
| } |
| int finalNode = curNode; |
| //loop till we get a FS that is of type eStringListType |
| while (cas.getHeapValue(curNode) == neIntListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| //TODO throw exc |
| } |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(intTailFeat)); |
| } |
| //set the tail feature to eStringListType fs |
| cas.setFeatureValue(finalNode, intTailFeat, curNode); |
| } else { |
| while (cas.getHeapValue(curNode) == neIntListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| int value = Integer.parseInt((String) stringValues.get(i++)); |
| cas.setFeatureValue(curNode,intHeadFeat, value ); |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(intTailFeat)); |
| } |
| } |
| if (foundCycle) { |
| reportWarning("Found a cycle in an IntegerList. List truncated to " |
| + i); |
| } |
| return first; |
| } |
| |
| public int updateFloatList(int addr, List<String> stringValues) throws SAXException { |
| int first = addr; |
| int currLength = this.getLength(this.neFloatListType, addr); |
| int curNode = addr; |
| int prevNode = 0; |
| IntRedBlackTree visited = new IntRedBlackTree(); |
| boolean foundCycle = false; |
| int i =0; |
| |
| //if (currLength != stringValues.size() ) { |
| // first = createFloatList(stringValues); |
| if (currLength < stringValues.size()) { |
| while (cas.getHeapValue(curNode) == neFloatListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| float value = Float.parseFloat(stringValues.get(i++)); |
| cas.setFeatureValue(curNode,floatHeadFeat, value); |
| prevNode = curNode; |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(floatTailFeat)); |
| } |
| //add nodes for remaining values |
| if (i < stringValues.size()) { |
| int emptyListFs = curNode; |
| //check that first is efloatlisttype |
| while (i < stringValues.size()) { |
| int newNode = cas.ll_createFS(neFloatListType); |
| float value = Float.parseFloat((String) stringValues.get(i++)); |
| cas.setFeatureValue(newNode,floatHeadFeat, value); |
| cas.setFeatureValue(newNode, floatTailFeat, emptyListFs); |
| cas.setFeatureValue(prevNode, floatTailFeat, newNode); |
| prevNode = newNode; |
| } |
| } |
| } else if (currLength > stringValues.size()) { |
| while (cas.getHeapValue(curNode) == neFloatListType && i < stringValues.size()) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| float value = Float.parseFloat((String) stringValues.get(i++)); |
| cas.setFeatureValue(curNode,floatHeadFeat, value); |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(floatTailFeat)); |
| } |
| int finalNode = curNode; |
| //loop till we get a FS that is of type eStringListType |
| while (cas.getHeapValue(curNode) == neFloatListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| //TODO throw exc |
| } |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(floatTailFeat)); |
| } |
| //set the tail feature to eStringListType fs |
| cas.setFeatureValue(finalNode, floatTailFeat, curNode); |
| } else { |
| while (cas.getHeapValue(curNode) == neFloatListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| float value = Float.parseFloat((String) stringValues.get(i++)); |
| cas.setFeatureValue(curNode,floatHeadFeat, CASImpl.float2int(value)); |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(floatTailFeat)); |
| } |
| } |
| |
| if (foundCycle) { |
| reportWarning("Found a cycle in an IntegerList. List truncated to " |
| + i); |
| } |
| return first; |
| } |
| |
| public int updateFsList(int addr, List<String> stringValues, IntVector fsAddresses) throws SAXException { |
| int first = addr; |
| int currLength = this.getLength(this.neFsListType, addr); |
| boolean foundCycle = false; |
| IntRedBlackTree visited = new IntRedBlackTree(); |
| int curNode = addr; |
| int prevNode = 0; |
| |
| //if (currLength != stringValues.size() ) { |
| // first = createFsList(stringValues, fsAddresses); |
| int i=0; |
| if (currLength < stringValues.size() ) { |
| while (cas.getHeapValue(curNode) == neFsListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| int value = Integer.parseInt(stringValues.get(i++)); |
| cas.setFeatureValue(curNode,fsHeadFeat, value); |
| fsAddresses.add(curNode); |
| prevNode = curNode; |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(fsTailFeat)); |
| } |
| //add nodes for remaining values |
| if (i < stringValues.size()) { |
| int emptyListFs = curNode; |
| //check that first is estringlisttype |
| while (i < stringValues.size()) { |
| int newNode = cas.ll_createFS(neFsListType); |
| int value = Integer.parseInt((String) stringValues.get(i++)); |
| cas.setFeatureValue(newNode,fsHeadFeat, value); |
| fsAddresses.add(newNode); |
| cas.setFeatureValue(newNode, fsTailFeat, emptyListFs); |
| cas.setFeatureValue(prevNode, fsTailFeat, newNode); |
| prevNode = newNode; |
| } |
| } |
| } else if (currLength > stringValues.size()) { |
| while (cas.getHeapValue(curNode) == neFsListType && i < stringValues.size()) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| int value = Integer.parseInt((String) stringValues.get(i++)); |
| fsAddresses.add(curNode); |
| cas.setFeatureValue(curNode,fsHeadFeat, value); |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(fsTailFeat)); |
| } |
| int finalNode = curNode; |
| //loop till we get a FS that is of type eStringListType |
| while (cas.getHeapValue(curNode) == neFsListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| //TODO throw exc |
| } |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(fsTailFeat)); |
| } |
| //set the tail feature to eStringListType fs |
| cas.setFeatureValue(finalNode, fsTailFeat, curNode); |
| } else { |
| while (cas.getHeapValue(curNode) == neFsListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| int value = Integer.parseInt((String) stringValues.get(i++)); |
| cas.setFeatureValue(curNode,fsHeadFeat, value); |
| fsAddresses.add(curNode); |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(fsTailFeat)); |
| } |
| } |
| if (foundCycle) { |
| reportWarning("Found a cycle in an IntegerList. List truncated to " |
| + i); |
| } |
| return first; |
| } |
| |
| public int updateStringList(int addr, List<String> stringValues) throws SAXException { |
| int first = addr; |
| boolean foundCycle = false; |
| IntRedBlackTree visited = new IntRedBlackTree(); |
| int curNode = addr; |
| int prevNode = 0; |
| int currLength = this.getLength(this.neStringListType, addr); |
| |
| if (currLength < stringValues.size() ) { |
| int i =0; |
| while (cas.getHeapValue(curNode) == neStringListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| String curValue = cas.getStringForCode(cas.getHeapValue(curNode |
| + cas.getFeatureOffset(stringHeadFeat))); |
| String newValue = stringValues.get(i++); |
| if (!curValue.equals(newValue)) { |
| cas.setFeatureValue(curNode, stringHeadFeat, cas.addString(newValue)); |
| } |
| prevNode = curNode; |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(stringTailFeat)); |
| } |
| //extend the list |
| if (i < stringValues.size()) { |
| int emptyListFs = curNode; |
| while (i < stringValues.size()) { |
| int newNode = cas.ll_createFS(neStringListType); |
| String value = (String) stringValues.get(i++); |
| cas.setFeatureValue(newNode, stringHeadFeat, cas.addString(value)); |
| cas.setFeatureValue(newNode, stringTailFeat, emptyListFs); |
| cas.setFeatureValue(prevNode,stringTailFeat, newNode); |
| prevNode = newNode; |
| } |
| } |
| } else if (currLength > stringValues.size()) { |
| int i=0; |
| while (cas.getHeapValue(curNode) == neStringListType && i < stringValues.size()) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| String curValue = cas.getStringForCode(cas.getHeapValue(curNode |
| + cas.getFeatureOffset(stringHeadFeat))); |
| String newValue = (String)stringValues.get(i++); |
| if (!curValue.equals(newValue)) { |
| cas.setFeatureValue(curNode, stringHeadFeat, cas.addString(newValue)); |
| } |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(stringTailFeat)); |
| } |
| int finalNode = curNode; |
| while (cas.getHeapValue(curNode) == neStringListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| //TODO throw exc |
| } |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(stringTailFeat)); |
| } |
| cas.setFeatureValue(finalNode, stringTailFeat, curNode); |
| } else { |
| int i =0; |
| while (cas.getHeapValue(curNode) == neStringListType) { |
| if (!visited.put(curNode, curNode)) { |
| foundCycle = true; |
| break; |
| } |
| String curValue = cas.getStringForCode(cas.getHeapValue(curNode |
| + cas.getFeatureOffset(stringHeadFeat))); |
| String newValue = (String)stringValues.get(i++); |
| if (!curValue.equals(newValue)) { |
| cas.setFeatureValue(curNode, stringHeadFeat, cas.addString(newValue)); |
| } |
| curNode = cas.getHeapValue(curNode + cas.getFeatureOffset(stringTailFeat)); |
| } |
| } |
| |
| if (foundCycle) { |
| reportWarning("Found a cycle in an IntegerList. List truncated. "); |
| } |
| return first; |
| } |
| |
| |
| |
| private void reportWarning(String message) throws SAXException { |
| if (this.logger != null) { |
| logger.log(Level.WARNING, message); |
| } |
| if (this.eh != null) { |
| this.eh.warning(new SAXParseException(message, null)); |
| } |
| } |
| } |