Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure thread safe for attribute currentNode #4

Merged
merged 1 commit into from
Jan 5, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@
}

private XMLStreamReader xmlStreamReader;
private static BMap<BString, Object> currentNode;
public static final String PARSE_ERROR = "failed to parse xml";
public static final String PARSE_ERROR_PREFIX = PARSE_ERROR + ": ";

Expand Down Expand Up @@ -152,7 +151,7 @@
handleXMLStreamException(e);
}

return currentNode;
return xmlParserData.currentNode;
}

private boolean parseXmlElements(int next, XmlParserData xmlParserData) throws XMLStreamException {
Expand Down Expand Up @@ -188,7 +187,7 @@
if (next == END_ELEMENT) {
QName endElement = xmlStreamReader.getName();
if (endElement.getLocalPart().equals(startElementName)) {
validateRequiredFields(currentNode, xmlParserData);
validateRequiredFields(xmlParserData);
xmlParserData.fieldHierarchy.pop();
xmlParserData.restTypes.pop();
xmlParserData.attributeHierarchy.pop();
Expand Down Expand Up @@ -217,7 +216,7 @@
}

RecordType rootRecord = xmlParserData.rootRecord;
currentNode = ValueCreator.createRecordValue(rootRecord);
xmlParserData.currentNode = ValueCreator.createRecordValue(rootRecord);
QualifiedName elementQName = getElementName(xmlStreamReader);
xmlParserData.rootElement =
DataUtils.validateAndGetXmlNameFromRecordAnnotation(rootRecord, rootRecord.getName(), elementQName);
Expand Down Expand Up @@ -263,17 +262,17 @@
throw DiagnosticLog.error(DiagnosticErrorCode.INVALID_TYPE, fieldType, PredefinedTypes.TYPE_STRING);
}

if (currentNode.containsKey(bFieldName)) {
if (xmlParserData.currentNode.containsKey(bFieldName)) {
if (!DataUtils.isArrayValueAssignable(fieldType.getTag())) {
throw DiagnosticLog.error(DiagnosticErrorCode.FOUND_ARRAY_FOR_NON_ARRAY_TYPE, fieldType, fieldName);
}

int arraySize = ((ArrayType) fieldType).getSize();
if (arraySize != -1 && arraySize <= ((BArray) currentNode.get(bFieldName)).getLength()) {
if (arraySize != -1 && arraySize <= ((BArray) xmlParserData.currentNode.get(bFieldName)).getLength()) {
return;
}

((BArray) currentNode.get(bFieldName)).append(convertStringToRestExpType(bText, fieldType));
((BArray) xmlParserData.currentNode.get(bFieldName)).append(convertStringToRestExpType(bText, fieldType));
return;
}

Expand All @@ -283,7 +282,7 @@
&& ((ArrayType) fieldType).getElementType().getTag() == TypeTags.RECORD_TYPE_TAG) {
handleContentFieldInRecordType((RecordType) ((ArrayType) fieldType).getElementType(), bText, xmlParserData);
} else {
currentNode.put(bFieldName, convertStringToRestExpType(bText, fieldType));
xmlParserData.currentNode.put(bFieldName, convertStringToRestExpType(bText, fieldType));
}
}

Expand All @@ -305,9 +304,9 @@
popStacks(xmlParserData);
for (String key : recordType.getFields().keySet()) {
if (key.contains(Constants.CONTENT)) {
currentNode.put(StringUtils.fromString(key),
xmlParserData.currentNode.put(StringUtils.fromString(key),
convertStringToExpType(text, recordType.getFields().get(key).getFieldType()));
currentNode = (BMap<BString, Object>) xmlParserData.nodesStack.pop();
xmlParserData.currentNode = (BMap<BString, Object>) xmlParserData.nodesStack.pop();
return;
}
}
Expand All @@ -317,8 +316,9 @@
return;
}

currentNode.put(StringUtils.fromString(Constants.CONTENT), convertStringToRestExpType(text, restType));
currentNode = (BMap<BString, Object>) xmlParserData.nodesStack.pop();
xmlParserData.currentNode.put(StringUtils.fromString(Constants.CONTENT),
convertStringToRestExpType(text, restType));
xmlParserData.currentNode = (BMap<BString, Object>) xmlParserData.nodesStack.pop();
}

private Object convertStringToExpType(BString value, Type expType) {
Expand Down Expand Up @@ -352,8 +352,8 @@
}

private Object buildDocument(XmlParserData xmlParserData) {
validateRequiredFields(currentNode, xmlParserData);
return currentNode;
validateRequiredFields(xmlParserData);
return xmlParserData.currentNode;
}

@SuppressWarnings("unchecked")
Expand All @@ -369,12 +369,13 @@
return;
}

validateRequiredFields(currentNode, xmlParserData);
currentNode = (BMap<BString, Object>) xmlParserData.nodesStack.pop();
validateRequiredFields(xmlParserData);
xmlParserData.currentNode = (BMap<BString, Object>) xmlParserData.nodesStack.pop();
popStacks(xmlParserData);
}

private void validateRequiredFields(BMap<BString, Object> currentMapValue, XmlParserData xmlParserData) {
private void validateRequiredFields(XmlParserData xmlParserData) {
BMap<BString, Object> currentMapValue = xmlParserData.currentNode;
Map<QualifiedName, Field> fields = xmlParserData.fieldHierarchy.peek();
for (QualifiedName key : fields.keySet()) {
// Validate required array size
Expand Down Expand Up @@ -410,11 +411,12 @@
xmlParserData.currentField = currentField;
if (xmlParserData.currentField == null) {
if (xmlParserData.restTypes.peek() != null) {
currentNode = handleRestField(xmlParserData);
xmlParserData.currentNode = handleRestField(xmlParserData);
}
return;
}

BMap<BString, Object> currentNode = xmlParserData.currentNode;
String fieldName = currentField.getFieldName();
Object temp = currentNode.get(StringUtils.fromString(fieldName));
BString bFieldName = StringUtils.fromString(fieldName);
Expand Down Expand Up @@ -456,7 +458,7 @@
xmlParserData.siblings = new LinkedHashMap<>();
xmlParserData.recordTypeStack.push(xmlParserData.rootRecord);
xmlParserData.rootRecord = recordType;
currentNode = updateNextValue(recordType, fieldName, fieldType, xmlParserData);
xmlParserData.currentNode = updateNextValue(recordType, fieldName, fieldType, xmlParserData);
QName qName = xmlStreamReader.getName();
DataUtils.validateTypeNamespace(qName.getPrefix(), qName.getNamespaceURI(), recordType);
handleAttributes(xmlStreamReader, xmlParserData);
Expand All @@ -466,6 +468,7 @@
XmlParserData xmlParserData) {
BMap<BString, Object> nextValue = ValueCreator.createRecordValue(rootRecord);
updateExpectedTypeStacks(rootRecord, xmlParserData);
BMap<BString, Object> currentNode = xmlParserData.currentNode;
Object temp = currentNode.get(StringUtils.fromString(fieldName));
if (temp instanceof BArray) {
int arraySize = ((ArrayType) fieldType).getSize();
Expand Down Expand Up @@ -498,7 +501,7 @@
QualifiedName restStartPoint = xmlParserData.parents.isEmpty() ?
xmlParserData.rootElement : getLastElementInSiblings(xmlParserData.parents.peek());
xmlParserData.restFieldsPoints.push(restStartPoint);
xmlParserData.nodesStack.push(currentNode);
xmlParserData.nodesStack.push(xmlParserData.currentNode);
return (BMap<BString, Object>) parseRestField(xmlParserData);
}

Expand Down Expand Up @@ -554,12 +557,13 @@
xmlParserData.siblings = new LinkedHashMap<>();
xmlParserData.siblings.put(elemQName, false);
BMap<BString, Object> temp =
(BMap<BString, Object>) currentNode.get(StringUtils.fromString(lastElement.getLocalPart()));
(BMap<BString, Object>) xmlParserData.currentNode.get(
StringUtils.fromString(lastElement.getLocalPart()));
BMap<BString, Object> next =
ValueCreator.createMapValue(DataUtils.getMapTypeFromConstraintType(restType));
temp.put(currentFieldName, next);
xmlParserData.nodesStack.add(currentNode);
currentNode = temp;
xmlParserData.nodesStack.add(xmlParserData.currentNode);
xmlParserData.currentNode = temp;
handleAttributesRest(xmlStreamReader, restType, next);
return currentFieldName;
}
Expand All @@ -568,25 +572,25 @@
xmlParserData.siblings.put(elemQName, false);
if (restType.getTag() == TypeTags.ARRAY_TAG) {
BArray tempArray = ValueCreator.createArrayValue(DataUtils.getArrayTypeFromElementType(restType));
currentNode.put(currentFieldName, tempArray);
xmlParserData.currentNode.put(currentFieldName, tempArray);
} else {
BMap<BString, Object> next =
ValueCreator.createMapValue(DataUtils.getMapTypeFromConstraintType(restType));
currentNode.put(currentFieldName, next);
xmlParserData.currentNode.put(currentFieldName, next);
handleAttributesRest(xmlStreamReader, restType, next);
}
return currentFieldName;
}

xmlParserData.parents.push(xmlParserData.siblings);
xmlParserData.siblings = new LinkedHashMap<>();
Object currentElement = currentNode.get(currentFieldName);
xmlParserData.nodesStack.add(currentNode);
Object currentElement = xmlParserData.currentNode.get(currentFieldName);
xmlParserData.nodesStack.add(xmlParserData.currentNode);

if (currentElement instanceof BArray) {
int elemTypeTag = ((BArray) currentElement).getElementType().getTag();
if (elemTypeTag == TypeTags.ANYDATA_TAG || elemTypeTag == TypeTags.JSON_TAG) {
currentNode = updateNextArrayMemberForRestType((BArray) currentElement, restType);
xmlParserData.currentNode = updateNextArrayMemberForRestType((BArray) currentElement, restType);
}
return currentFieldName;
}
Expand All @@ -597,11 +601,11 @@
}
BArray tempArray = ValueCreator.createArrayValue(DataUtils.getArrayTypeFromElementType(restType));
tempArray.append(currentElement);
currentNode.put(currentFieldName, tempArray);
xmlParserData.currentNode.put(currentFieldName, tempArray);

int elemTypeTag = tempArray.getElementType().getTag();
if (elemTypeTag == TypeTags.ANYDATA_TAG || elemTypeTag == TypeTags.JSON_TAG) {
currentNode = updateNextArrayMemberForRestType(tempArray, restType);
xmlParserData.currentNode = updateNextArrayMemberForRestType(tempArray, restType);
}
return currentFieldName;
}
Expand All @@ -624,7 +628,7 @@
return;
}

currentNode = (BMap<BString, Object>) xmlParserData.nodesStack.pop();
xmlParserData.currentNode = (BMap<BString, Object>) xmlParserData.nodesStack.pop();
xmlParserData.siblings = xmlParserData.parents.pop();
if (xmlParserData.siblings.containsKey(elemQName) && xmlParserData.restFieldsPoints.remove(elemQName)) {
xmlParserData.fieldHierarchy.pop();
Expand Down Expand Up @@ -658,19 +662,19 @@
throw DiagnosticLog.error(DiagnosticErrorCode.INVALID_TYPE, restType, PredefinedTypes.TYPE_STRING);
}

Object currentElement = currentNode.get(currentFieldName);
Object currentElement = xmlParserData.currentNode.get(currentFieldName);
BMap<BString, Object> parent = (BMap<BString, Object>) xmlParserData.nodesStack.peek();
Object result = convertStringToRestExpType(bText, restType);

if (currentElement == null && !currentNode.isEmpty()) { // Add text to the #content field
currentNode.put(StringUtils.fromString(Constants.CONTENT), result);
currentNode = parent;
if (currentElement == null && !xmlParserData.currentNode.isEmpty()) { // Add text to the #content field
xmlParserData.currentNode.put(StringUtils.fromString(Constants.CONTENT), result);
xmlParserData.currentNode = parent;

Check warning on line 671 in native/src/main/java/io/ballerina/stdlib/data/xmldata/xml/XmlParser.java

View check run for this annotation

Codecov / codecov/patch

native/src/main/java/io/ballerina/stdlib/data/xmldata/xml/XmlParser.java#L670-L671

Added lines #L670 - L671 were not covered by tests
} else if (currentElement instanceof BArray) {
((BArray) currentElement).append(result);
} else if (currentElement instanceof BMap && !((BMap<BString, Object>) currentElement).isEmpty()) {
((BMap<BString, Object>) currentElement).put(StringUtils.fromString(Constants.CONTENT), result);
} else {
currentNode.put(currentFieldName, result);
xmlParserData.currentNode.put(currentFieldName, result);
}
}

Expand Down Expand Up @@ -720,7 +724,7 @@
for (BString annotationKey : annotations.getKeys()) {
String keyStr = annotationKey.getValue();
if (keyStr.contains(Constants.FIELD) && DataUtils.isAttributeField(annotationKey, annotations)) {
String attributeName = keyStr.split("\\$field\\$\\.")[1].replaceAll("\\\\", "");
String attributeName = keyStr.split(Constants.FIELD_REGEX)[1].replaceAll("\\\\", "");
Map<BString, Object> fieldAnnotation = (Map<BString, Object>) annotations.get(annotationKey);
QualifiedName fieldQName = DataUtils.getFieldNameFromRecord(fieldAnnotation, attributeName);
fieldQName.setLocalPart(getModifiedName(fieldAnnotation, attributeName));
Expand Down Expand Up @@ -754,7 +758,7 @@
}

try {
currentNode.put(StringUtils.fromString(field.getFieldName()), convertStringToExpType(
xmlParserData.currentNode.put(StringUtils.fromString(field.getFieldName()), convertStringToExpType(
StringUtils.fromString(xmlStreamReader.getAttributeValue(i)), field.getFieldType()));
} catch (Exception e) {
// Ignore: Expected type will mismatch when element and attribute having same name.
Expand Down Expand Up @@ -785,7 +789,7 @@
switch (restType.getTag()) {
case TypeTags.RECORD_TYPE_TAG -> {
RecordType recordType = (RecordType) restType;
currentNode = updateNextValue(recordType, fieldName, restType, xmlParserData);
xmlParserData.currentNode = updateNextValue(recordType, fieldName, restType, xmlParserData);
handleAttributes(xmlStreamReader, xmlParserData);
parseRecordRest(fieldName, xmlParserData);
xmlParserData.siblings.clear();
Expand All @@ -796,11 +800,12 @@
Type elemType = TypeUtils.getReferredType(arrayType.getElementType());
if (elemType.getTag() == TypeTags.RECORD_TYPE_TAG) {
// Create an array value since expected type is an array.
if (!currentNode.containsKey(StringUtils.fromString(fieldName))) {
currentNode.put(StringUtils.fromString(fieldName),
if (!xmlParserData.currentNode.containsKey(StringUtils.fromString(fieldName))) {
xmlParserData.currentNode.put(StringUtils.fromString(fieldName),
ValueCreator.createArrayValue(DataUtils.getArrayTypeFromElementType(elemType)));
}
currentNode = updateNextValue((RecordType) elemType, fieldName, arrayType, xmlParserData);
xmlParserData.currentNode =
updateNextValue((RecordType) elemType, fieldName, arrayType, xmlParserData);
handleAttributes(xmlStreamReader, xmlParserData);
parseRecordRest(fieldName, xmlParserData);
xmlParserData.siblings.clear();
Expand Down Expand Up @@ -843,5 +848,6 @@
private QualifiedName rootElement;
private final Stack<LinkedHashMap<QualifiedName, Boolean>> parents = new Stack<>();
private LinkedHashMap<QualifiedName, Boolean> siblings = new LinkedHashMap<>();
private BMap<BString, Object> currentNode;
}
}
Loading